Creating StateListDrawables for multiple custom ViewGroup components from a share

I created a class that extends ViewGroup. One of the functions of this class, MyCustomViewGroup, acts as a container for the nested class MyButton, which extends Button.

I am setting custom properties for MyCustomViewGroup from a custom AttributeSet in the usual way. One of the attributes defines StateListDrawable for use against the background of instances of the nested class MyButton. I store this in the class variable mMyButtonBackground.

public class MyCustomViewGroup extends ViewGroup { private Drawable mMyButtonBackground; ... 

Every time I create a new instance of MyButton in MyCustomViewGroup, I set it as a background.

  MyButton myButton = new MyButton(context); myButton.setBackground(mMyButtonBackground); 

At run time, StateListDrawable seems to work only for the last instance of MyButton added.

For example, I create 4 instances of MyButton in MyCustomViewGroup. If I click on MyButton number 4, this will change the background as defined in StateListDrawable. If I click on MyButton from 1 to 3, their background will not change, but MyButton number 4. does.

Logically, this suggests that this is a problem with variability. All MyButton instances use the same StateListDrawable stored in mMyButtonBackground. Given this, I tried:

  MyButton myButton = new MyButton(context); Drawable myButtonBackground = mMyButtonBackground.mutate(); myButton.setBackground(myButtonBackground); 

This did not solve the problem. I also tried using it as a StateListDrawable:

  MyButton myButton = new MyButton(context); StateListDrawable myButtonBackground = (StateListDrawable)mMyButtonBackground.mutate(); myButton.setBackground(myButtonBackground); 

This also did not solve the problem. In my studies trying to solve this problem, I read this article by Romain Gai about Drawable mutations . I would think that since StateListDrawable is a subclass of Drawable, I should be able to take the same approach, but I can't get it to work. What am I missing?

+4
source share
3 answers

After pskink's answer, the problem is that you are using the same instance of Drawable . When you set Drawable as the background, the View register as a listener for that Drawable to receive events (to take into account the new stat Drawable , also requiring redrawing the View ). That way, your only StateListDrawable instance StateListDrawable always have a callback for the last View for which a background image is set. Therefore, it works for the last Button , but it also redraws the same Button when you work on the other Buttons , since Drawable is invalid for the View callback.

You could simply avoid this by creating a new StateListDrawable for each Button . In a container container, you can simply pass an attribute with a String representing the name StateListDrawable for use as a background, save it and use it when creating a new Buttons :

 String mBtnDrawable = ""; //initialize in the constructor // creating new Buttons MyButton myButton = new MyButton(context); int drawableId = getContext().getResources().getIdentifier(mBtnDrawable, "drawable", getContext().getPackageName()); StateListDrawable bck = (StateListDrawable) getContext().getResources().getDrawable(drawableId); // maybe also mutate it? myButton.setBackground(bck); 
+3
source

you cannot share one SLD instance with several views, you need one SLD per view, sorry

+7
source

According to what the Resources class ( Resources.java ) does, I have found that the code below can solve your problem.

 Drawable selector = res.getDrawable(R.drawable.setting_btn_pressed_selector); view1.setBackgroundDrawable(selector.getConstantState().newDrawable()); view2.setBackgroundDrawable(selector.getConstantState().newDrawable()); view3.setBackgroundDrawable(selector.getConstantState().newDrawable()); 

But I do not know the side effect of this code. Somebody knows? You can leave a comment or indicate my mistake.

0
source

All Articles