For example, if I have:
EditText A;
TextView B;
ImageView C;
And I want to set all their visibilities to View.GONE, how can I do it in a way that instead of this:
A.setVisibility(View.GONE);
B.setVisibility(View.GONE);
C.setVisibility(View.GONE);
I do this:
groupD.setVisibility(View.GONE);
without having to put all of them in one RelativeLayout and then setting the RelativeLayout to View.GONE? Is there a Java class for this? Or do I have to get a library for it?
If not, can I do it manually so I can organize my project which has 30 views? I don't want to set each group to be in its own RelativeLayout because all views are dependent on each other.
With ButterKnife you can do:
#BindViews({ R.id.A, R.id.B, R.id.C })
List<View> views;
ButterKnife.apply(views, VISIBLE);
ButterKnife.apply(views, GONE);
//Action and Setter interfaces allow specifying simple behavior.
static final ButterKnife.Action<View> VISIBLE = new ButterKnife.Action<View>() {
#Override public void apply(View view, int index) {
view.setVisibility(View.VISIBLE);
}
};
static final ButterKnife.Action<View> GONE = new ButterKnife.Action<View>() {
#Override public void set(View view, int index) {
view.setVisibility(View.GONE);
}
};
Example adapted from the website
The best way will be passing the views to a single method. All of them are Views, so you can do something like this.
public void setViews(View view){
view.setVisibility(View.GONE);
}
And call the method like this:
setViews(editText);
Related
I m new here and I've got a question for which I haven't found answer yet.
I am trying to get some variable value from a clicked object using onClickListener.
This view is an object (actually its a ConstraintLayout) created previously with a boolean value.
Code (that is not the current code I've got but you get the idea hopefully):
public class layoutView extends ConstraintLayout {
boolean bool = false;
public layoutView (Context context) {
super(context);
}
...
}
I am adding this layoutView into my main layout and its working fine but I need to get this boolean value when i click the layout view.
layoutView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setBackgroundColor(Color.GREEN); //this works fine
boolean check = v.bool //this wouldnt work
if (v.bool == true)... //this woulnt work
}
});
Is it possible at all. How to approach this?
Thanks in advance!
You can try layoutView.setTag()/getTag() instead of keeping your own variable bool.
Note that you may need to use a Boolean object instead of primitive type, for example:
layoutView.setTag(new Boolean(true));
// inside on click listener
if (v.getTag() == true) {
// do something
}
For our application I had to implement a nested RecyclerView. I'm getting a list of Tables from JSON and every Table has another list with groups from each table. I can get everything on the screen as requested, the problem is the selection.
I have 2 different RecyclerViews on the screen and I can not seem to get a single selection working in this environment, especially after scrolling. Every group and every table has a Toggle Button, and only one can be active at a time.
This is how the main screen looks like
So far I've tried putting a boolean isSelected on the Model but that didn't work out at all. The closest solution I came up with was a helper class that searches every CompoundButton on-screen and deselects them all when one is selected. The problem is this helper class cant get the Buttons which are off-screen.
How I populate ParentAdapter (in MainActivity):
public void setAdapter(List<Table> tableList)
{
RecyclerView recycler_view_parent = findViewById(R.id.recyclerparent);
LinearLayoutManager manager=new LinearLayoutManager(MainActivity.this);
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
recycler_view_parent.setLayoutManager(manager);
recycler_view_parent.setHasFixedSize(true);
recycler_view_parent.setItemViewCacheSize(tableList.size());
ParentAdapter parentAdapter=new ParentAdapter(tableList,MainActivity.this);
recycler_view_parent.setAdapter(parentAdapter);
}
How i populate ChildAdapter (in onBindViewHolder of ParentAdapter):
FlexboxLayoutManager manager = new FlexboxLayoutManager(context);
manager.setFlexDirection(FlexDirection.COLUMN);
manager.setJustifyContent(JustifyContent.FLEX_START);
manager.setFlexWrap(FlexWrap.WRAP);
manager.setAlignItems(AlignItems.BASELINE);
holder.recycler_view_child.setLayoutManager(manager);
holder.recycler_view_child.setHasFixedSize(true);
adapter = new ChildAdapter(tableList, tableList.get(position).getGroups(), context);
holder.recycler_view_child.setAdapter(adapter);
The desired output should be only 1 Table OR Group at a time can be toggled (in total, not one from every RecyclerView) and the state should be the same after scrolling/device rotation).
I did a lot of research over the last days on this subject and I can not seem to find a working example of nested RecyclerView with single selection over both RVs.
So does anyone have an idea on how to solve this? I think the biggest issue is telling the Parent that a Button in Child was toggled and vice-versa.
I think for the ParentAdapter it should look something like this:
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, final int position) {
final Table table = tablelist.get(position);
ViewHolder viewHolder = (ViewHolder) holder;
if (table.isTableSelected()) {
viewHolder.toggletable.setChecked(true);
lastToggled = position;
} else {
viewHolder.toggletable.setChecked(false);
}
viewHolder.toggletable.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
if (b) {
table.setTableSelected(true);
// notify ChildAdapter and group.setGroupSelected(false)
if (lastToggled >= 0) {
tablelist.get(lastToggled).setTableSelected(false);
// notify ChildAdapter and group.setGroupSelected(false)
notifyItemChanged(lastToggled);
}
lastToggled = position;
} else {
table.setTableSelected(false);
}
}
});
}
Thanks in advance.
UPDATE: Managed to come up with a solution myself, although 100% sure, not the best approach.
First of all, implement Greenrobots EventBus:
implementation 'org.greenrobot:eventbus:3.1.1'
Now in the Activity where you hold both RecyclerViews register the Event listener:
#Override
protected void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
and subscribe 2 methods. One for Parent Events and one for Children Events. This methods will trigger every time an item is selected!
#Subscribe(threadMode = ThreadMode.MAIN)
public void onParentEventClicked(ParentAdapter.ParentEvent event) {
// to access the inner adapter here you must set it to public in the ParentAdapter(public ChildAdapter adapter;)
adapter.adapter.deSelectChild();
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onChildEventClicked(ChildAdapter.ChildEvent event) {
// normal ParentAdapter reference(ParentAdapter adapter;)
adapter.deSelectParent();
}
Inside your ParentAdapter create a method to deselect all parent items and a static class to fire the event:
public void deSelectParent()
{
for (int i=0;i<data.size();i++)
{
data.get(i).setSelected(false);
}
notifyDataSetChanged();
}
public static class ParentEvent {
View view;
int position;
}
Inside your ChildAdapter create a method to deselect all child items and a static class to fire the event:
public void deSelectChild()
{
for (int i=0;i<data.size();i++)
{
datachild.get(i).setSelected(false);
}
notifyDataSetChanged();
}
public static class ChildEvent {
View view;
int position;
}
now in both Parent and Child onBindViewHolders, you need similar logic for your models:
if (item.isSelected()) {
holder.yourbutton.setChecked(true);
} else {
holder.yourbutton.setChecked(false);
}
holder.yourbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ParentEvent event = new ParentEvent();
event.view = holder.yourbutton;
event.position = position;
EventBus.getDefault().post(event);
if (holder.yourbutton.isChecked()) {
for (int i = 0; i < data.size(); i++) {
data.get(i).setSelected(false);
}
data.get(position).setSelected(true);
} else {
data.get(position).setSelected(false);
}
notifyDataSetChanged();
}
});
And thats pretty much it, every click on a ParentItem will trigger the deselect method for ChildAdapter and vice-versa.
Due to the high usage of notifyDataSetChanged() I recommend using this line to get rid of the blinking:
recycler_view_parent.setItemAnimator(null);
Any problems let me know!
It is possible to create a click effect/animation for all clicks on my application?
Since I want this behaviour for all clicks events on my application, how should I do this? Is this bad for performance or resources of the smartphone?
It is hard to know without understanding the stack that has been built, that being said I think there are some safer and less methodologies to an onclick event that is the same across the board. For one I would not change fundamental nature of the "onClick" function, the lower level you mess with the more dangerous it is. That being said I think I would create my own version/function of onclick, maybe boomClick, where boomClick creates the animation that you want. Referencing a single function will barely decrease performance at all.
So, after a day working at this I managed to accomplish the expected behaviour.
Basically, I create my own Activity class which will do the animation work with the help of a custom lib. I'll try to explain what I did for future reference:
1. Add this lib to your project:
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.3'
2. Add these dimens to your "dimens.xml" file:
<dimen name="click_animation">100dp</dimen>
<dimen name="click_compensation">50dp</dimen>
3. Make the top parent of your activities layout a "RelativeLayout" and set a custom id:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/main_layout">
... the rest of the layout ...
</RelativeLayout>
4. Create your own "Activity" class:
public class MyActivity extends AppCompatActivity {
private RelativeLayout.LayoutParams params;
public void setClickAnimation(final Activity activity) {
// if you want to change the size of the animation, change the size on the dimens.xml
int size = (int) activity.getResources().getDimension(R.dimen.click_animation);
params = new RelativeLayout.LayoutParams(size, size);
// you want the parent layout of the activity
final RelativeLayout view = (RelativeLayout) activity.findViewById(R.id.main_layout);
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// you maybe won't need this compensation value
int compensation = (int) activity.getResources().getDimension(R.dimen.click_compensation);
try { startAnimation(view, (int) event.getX() - compensation, (int) event.getY() - compensation); }
catch (IOException e) { e.printStackTrace(); }
}
return true;
}
});
}
private void startAnimation(RelativeLayout view, int x, int y) throws IOException {
params.leftMargin = x;
params.topMargin = y;
// those are from the lib you imported
final GifImageView anim = new GifImageView(this);
// if you don't have it yet, put the gif you want on the assets folder
final GifDrawable gifFromResource = new GifDrawable(getAssets(), "click_animation.gif");
gifFromResource.addAnimationListener(new AnimationListener() {
#Override
public void onAnimationCompleted(int loopNumber) {
anim.setVisibility(View.GONE);
gifFromResource.stop();
gifFromResource.recycle();
}
});
anim.setBackground(gifFromResource);
gifFromResource.start();
view.addView(anim, params);
}
}
5. Make your Activities extend your "Activity" class:
public class FirstScreen extends MyActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.cards_screen);
// call the method you created and pass the activity context
setClickAnimation(this);
}
}
As for resources spent: this looks like a good solution and I am getting a good performance. The application seems to not be wasting a lot of resources with this solution.
Is there any way to change multiple TextView text sizes all at once? Also they may or may not be in single ViewGroup. I was hoping of doing by creating some kind of trigger/event that would act like pub/sub but got no ideas. Any Possibility?
You could just use a class which you register the TextViews with. Then have a method which goes through all the registered TextViews and sets the font size. Somethings like:
public class TextViewTextSizer {
private List<TextView> textViews;
public TextViewTextSizer() {
textViews = new ArrayList<>();
}
public void registerTextView(TextView textView) {
textViews.add(textView);
}
public void setTextSize(float size) {
for (TextView textView : textViews) {
textView.setTextSize(size);
}
}
}
I wrote a code for Spinner to bind array of USA States with Spinner in Android. But the problem is it shows reference type data in Spinner item, see the pic
I add android.R.layout.simple_spinner_dropdown_item but not know that what to add in layout. I checked many exemples on google and they add simple_spinner_dropdown_item but i could not find that what to add in layout. below is output and code. I want to show states in list instead of this junky data.
Spinner spStates = new Spinner(this);
spStates.setLayoutParams(new LayoutParams(screenWidth, LayoutParams.WRAP_CONTENT));
final USAStates states[] = new USAStates[51];
states[0] = new USAStates("Alabama", "AL");
states[1] = new USAStates("Alaska", "AK");
states[2] = new USAStates("Arizona", "AZ");
ArrayAdapter<USAStates> adapter = new ArrayAdapter<USAStates>(this, android.R.layout.simple_spinner_item, states);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spStates.setAdapter(adapter);
spStates.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
USAStates d = states[position];
Toast.makeText(getApplicationContext(), d.getStateAbrivation(), Toast.LENGTH_LONG).show();
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
public class USAStates {
private String _Statename;
private String _StateAbrivation;
public USAStates(String pStatename, String pStateAbrivation) {
Statename(pStatename);
StateAbrivation(pStateAbrivation);
}
public void Statename(String pStatename) {
_Statename = pStatename;
}
public void StateAbrivation(String pStateAbrivation) {
_StateAbrivation = pStateAbrivation;
}
public String getStatename() {
return _Statename;
}
public String getStateAbrivation() {
return _StateAbrivation;
}
}
Not sure, just doing this off the top of my head but, in your USAState class override your toString method.As is it maybe that the adapter is using the default toString() hence your weird text displaying (which I presume is the class name of the USAStates class)
for example
#Override
public String toString(){
return _Statename
}
I originally accepted the toString() answer but have since found that this doesn't appear to be right.
I had an ActionBar with spinner/drop down list and my adapter items were rendering with String.toString() value instead of of the title I set in the custom adapter. Adding toString() did fix initially until I tried to set a compound drawable in the same layout.
I needed to override getDropDownView as well as getViewin my adapter.
Having to override toString() is symptomatic that you haven't overridden the right methods in your adapter.
When overriding getDropDownView having to override toString() is no longer required and everything works as expected.
And the answer on the following post is a great way to implement by using the super method:
alternating colors of spinner items