2

How to achieve an android:background change effect on multiple Views at the same time, on clicking any of them?

Note that contents vary

I got a "badge" layout in two parts. They act like one button, but the two parts have different StateListDrawable (selectors) defining backgrounds for state_pressed etc. The first part is a header ("lefter") with an image. The second is a content area getting filled with various sub-contents. It all comes down to that the contents of the both parts both come in various sizes.

I want the two badge parts to stretch separately AND share a common background effect when any of them is pressed.

<LinearLayout
    style="@style/Badge">

    <!-- LEFTER -->
    <LinearLayout
            style="@style/BadgeLefter"
            android:background="@drawable/badge_lefter_bg_blue">
            <ImageView
                    style="@style/BadgeLefterImage"
                    android:src="@drawable/office_building"/>
    </LinearLayout>

    <!-- CONTENT -->
    <LinearLayout
            android:id="@+id/badge_blue_content"
            style="@style/BadgeContent"
            android:background="@drawable/badge_content_bg_blue">
    </LinearLayout> 
</LinearLayout>

Example of StateListDrawable background selector (like @drawable/badge_content_bg_blue above):

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_pressed="false"
    android:drawable="@drawable/badge_bg_blue_normal"/>
<item android:state_focused="false" android:state_pressed="true"
    android:drawable="@drawable/badge_bg_blue_pressed"/>
<item android:state_focused="true"
    android:drawable="@drawable/badge_bg_blue_focused"/>
<item android:state_focused="true" android:state_pressed="true"
    android:drawable="@drawable/badge_bg_blue_pressed"/>
</selector>

where badge_bg_blue_normal etc are 9-patch png's.

I'm new to android. I failed to find a similar question here. It does not help to custom my own Button because buttons only have one android:background selector. I found no 9-patch supporting multiple stretchable areas. I realize I could build a custom component. Is that a good idea here?

I use my badges widely around the app. An elegant solution would be greatly appreciated! :)

* SOLUTION EDIT: *

After building a custom component with a TouchListener I'm all set: ^_^

public class Badge extends LinearLayout {
    //...
    public Badge(Context c, AttributeSet attrs) {
        super(c, attrs);
        //... 
        // inflating layouts and setting selector backgrounds here
        //... 
        setClickable(true);
        setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {

                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    lefter.setPressed(true);
                    contents.setPressed(true);
                }
                else if (event.getAction() == MotionEvent.ACTION_UP || !isInside(v, event)) {
                    lefter.setPressed(false);
                    contents.setPressed(false);
                }
                return false;
            }

            private boolean isInside(View v, MotionEvent event) {
                //...
            }
        });
   }
   //...
}
JOG
  • 5,590
  • 7
  • 34
  • 54

1 Answers1

1

If I understand your question correctly, you have two buttons, and upon pressing one of them, both of them should behave like they are being pressed?

Upon pressing one of the buttons, did you try to call the View.setPressed(bool) function on the other one, and so on? That's where I would start if I had design like yours above. If that doesn't work, another approach could be to simply switch the background drawable on all buttons when pressing one of them, and simply not use the built-in state_pressed functionality.

Regarding 9-patches that are stretchable in multiple areas, you can achieve this using the 9-patch-tool included in the android SDK. I did it with a button I made myself which had a static center area (vertically) and two stretchable areas above and below.

jake_hetfield
  • 3,388
  • 1
  • 23
  • 30
  • Yes, that is a pretty correct interpretation of my question. Thank you, I will try that. ^_^ – JOG May 16 '11 at 11:59
  • To make the implementation more reusable, it could be an idea to implement a new View, (a subclass View or a subclass of Button), with the layout above. When the state is changed on the top view simply change the state of both inner views. Then you can reuse this new view class anywhere you need a new button. – jake_hetfield May 16 '11 at 13:06
  • (like Custom Component - "The basic approach" in the guide you mention) – jake_hetfield May 16 '11 at 13:16
  • Multi-stretchable 9-patch: How do you specify which content goes to which area? – JOG May 16 '11 at 13:55
  • Black non-transparent pixels on leftmost pixel column = vertically stretchable area. Black non-transparent pixels on topmost pixelrow = horizontally stretchable area. To have two stretchable areas in any direction, simply leave a white gap where the content is non-stretchable. – jake_hetfield May 16 '11 at 15:20
  • Epilogue: 9-patches with multiple stretchable areas was not what I was looking for, as there is no way to put different content in different areas. In my images above the house image and the contents to the right may change irrespectably. I instead extended `LinearLayout` and added a `TouchListener`: see post below. – JOG May 17 '11 at 15:21