8

I have a 9patch set as the background of my layout. However I still want to provide touch feedback by using the selectableItemBackground attr.

I've tried using a <layer-list> with the 9patch and selectableItemBackground as the android:drawable of the second <item>, however that did not work.

I could also try making a selector and overlay the gradient drawable android uses for selectableItemBackground in list_selector_background_pressed.xml with a <layer-list>. But in 4.4 KitKat the selected background color is actually gray instead of blue in JellyBeans, so I can't really hardcode it :(

There has to be an easier way, right guys? D:

Jason Hu
  • 1,237
  • 2
  • 15
  • 29

1 Answers1

16

I've tried using a with the 9patch and selectableItemBackground as the android:drawable of the second , however that did not work.

Yes, drawable attribute in a layer-list (or state-list) does not accept an attr value. You would see a Resource.NotFoundException. A look at LayerDrawable's (or StateListDrawable's) source code explains why: the value that you provide is assumed to be a drawable's id.

But, you can retrieve a theme and platform-specific drawable for an attribute in code:

// Attribute array
int[] attrs = new int[] { android.R.attr.selectableItemBackground };

TypedArray a = getTheme().obtainStyledAttributes(attrs);

// Drawable held by attribute 'selectableItemBackground' is at index '0'        
Drawable d = a.getDrawable(0);

a.recycle();

Now, you can create a LayerDrawable:

LayerDrawable ld = new LayerDrawable(new Drawable[] {

                       // Nine Path Drawable
                       getResources().getDrawable(R.drawable.Your_Nine_Path), 

                       // Drawable from attribute  
                       d });

// Set the background to 'ld'
yourLayoutContainer.setBackground(ld);

You'll also need to set yourLayoutContainer's clickable attribute:

android:clickable="true"
Vikram
  • 51,313
  • 11
  • 93
  • 122
  • This looks interesting. Will try. – Jason Hu Dec 02 '13 at 22:19
  • @JasonHu Sorry, I didn't go over your comment fully, was on a call. If you have a question, go ahead. – Vikram Dec 02 '13 at 23:00
  • Amazing. Works like a charm. I initially thought I would have to make a selector for the selected states (9patch only on default and the LayerDrawable when selected). But it seems the drawable you get back from the selectableItemBackground is actually the selector itself. Thank you. – Jason Hu Dec 02 '13 at 23:00
  • 1
    One thing to note for people that might attempt to do this. Make sure to save your padding on the view before you set the background dynamically with a 9patch, and set it back after the background has been set. Apparently the 9patch will make you lose the paddings on the view. http://stackoverflow.com/questions/10095196/whered-padding-go-when-setting-background-drawable – Jason Hu Dec 02 '13 at 23:03
  • @JasonHu Exactly. And since we're creating a LayerDrawable --> state-changes are passed to both drawables. `selectableItemBackground` is transparent when state-less. And that's why, this works. – Vikram Dec 02 '13 at 23:04
  • I will give the bounty to you after the 1st day lock on it goes away. – Jason Hu Dec 02 '13 at 23:06
  • @JasonHu Interesting bit of info. I wasn't aware of the padding issue. Thanks! – Vikram Dec 02 '13 at 23:07
  • 1
    Vikram & @JasonHu, both of you guys just saved me loads of hours. Thanks! – jenzz Jan 30 '15 at 14:30