Android: how to use view states with nested drawable resources? - android

I'm trying to create complex drawable with one picture inside changing with main view state change. My current resource looks like that
<transition xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<layer-list>
<item>
<selector>
<item android:state_activated="true" android:drawable="#drawable/img_activated_icon" />
<item android:drawable="#drawable/img_default_icon" />
</selector>
...
Next I use it as src for my ImageView.
The whole drawable renders fine but the selector ignores setActive() call on the ImageView and always displays "default" icon.
What am I doing wrong?
UPD
So, here goes the desired drawable hierarchy:
layer-list
transition
background1
background2
image
I was unable to activate transition animation in this case so I moved the transition to the upper level:
transition
layer-list
background1
image
layer-list
background2
image (the same image!)
So, how can I implement the first layout and be able both to control the transition and to change source for the image?

So basically you want to be able to control the drawables manually, and have them react to state changes. To my knowledge, it is bad practice to try to set a fake state (pressed/focused/etc) on a View, so I would recommend you don't try to do that. I haven't done this before, but I can't see why it couldn't be done. My idea would be to create a single LevelList of StateLists for this button/image.
The LevelList would provide you to have control over what "theme" the button/image has depending on the level you set it to using setLevel(). Each level would point to a "themed" StateList that would have different "themed" drawables for all the various states (pressed/focused/etc).
http://developer.android.com/guide/topics/resources/drawable-resource.html#LevelList
http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="0" android:drawable="#drawable/state_list_icon_default" />
<item android:maxLevel="1" android:drawable="#drawable/state_list_icon_another_style_1" />
<item android:maxLevel="2" android:drawable="#drawable/state_list_icon_another_style_2" />
</level-list>
Your state_list_icon_default would have your default drawables, like this (it's up to you what states you want to have drawables for):
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/img_default_icon_pressed" />
<item android:state_enabled="true" android:state_focused="true" android:drawable="#drawable/img_default_icon_focused" />
<item android:state_enabled="false" android:state_focused="true" android:drawable="#drawable/img_default_icon_disabled_focused" />
<item android:state_enabled="false" android:drawable="#drawable/img_default_icon_disabled" />
<item android:drawable="#drawable/img_default_icon"/>
</selector>
Here's some tutorials to see more in depth implementations.
http://iserveandroid.blogspot.com/2010/10/progress-bar-implementation-using-level.html
http://sermojohn.wordpress.com/2012/02/04/using-a-state-list-drawable-as-a-button-background-image/

Related

Animate a ChoiceChips' background color on selector state change

I'm trying to achieve a choice chip group like shown in the material documentation:
Link to Animation Video
Currently, I'm just using a selector as a background drawable:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorAccent" android:state_enabled="true" android:state_selected="true" />
<item android:color="#color/md_white_1000" />
</selector>
Switching those colors given above shall be animated.
If possible, the animation/transition should be compatible to api 17.
Currently, this is only possible with a custom view.
There's an open issue on MDC to implement animatable backgrounds:
https://issuetracker.google.com/issues/130410732

Setting button drawable for RadioButton using drawable xml not working for checked state

I've got a group of radio buttons, and I want to set the button's background to a solid color when checked. I created a drawable resource, using a selector and item def's like:
<item android:state_checked="true" android:state_pressed="false"
android:drawable="#color/app_tint"/>
with several variations while trying to get it to work. In the layout containing the buttons, I've tried setting both button and background properties (not at the same time, just one or the other in testing) like:
android1:background="#drawable/radio_state"
OR
android1:button="#drawable/radio_state"
I've read several posts, and I feel I'm close, just missing something to get it done. Thanks.
Here's one we did for an app:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_bcnav_ebilling_focus"
android:state_checked="true" />
<item android:drawable="#drawable/ic_bcnav_ebilling_focus"
android:state_selected="true" />
<item android:drawable="#drawable/ic_bcnav_ebilling_focus"
android:state_pressed="true" />
<item android:drawable="#drawable/ic_bcnav_ebilling_focus"
android:state_focused="true" />
<item android:drawable="#drawable/ic_bcnav_ebilling" />
</selector>
Each state has a different drawable, although in this example, we don't really care about all states being very different - just focus=true get a highlighted drawable (it has "..._focus")

Is to possible to have a single xml for multiple button states in android?

I have 6 image buttons in my activity each having different images..
For those 6 image buttons I am having 6 xml of button states in drawable folder for each button.
Is there any way or method so that I can club all the 6 xml into 1 single xml?
Yes, you can. You need not have 6 xmls for 6 different images, and then one more xml for combining the 6 XML files.
You can just have one XML, that contains all the state images.
Check this sample.
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="#drawable/btn_default_normal_disable" />
<item android:state_pressed="true"
android:drawable="#drawable/btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="#drawable/btn_default_selected" />
<item android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_focused="true"
android:drawable="#drawable/btn_default_normal_disable_focused" />
<item
android:drawable="#drawable/btn_default_normal_disable" />
</selector>
As you can see, in this single xml, you can refer to the images(drawables), directly.
android:drawable="#drawable/btn_default_selected"
please read:
http://developer.android.com/training/improving-layouts/reusing-layouts.html
As to findViewById(), you will have sub-views with identical ids; to find these views, you will have to find the root view and use that view to find-by-id its child view. (You can e.g. use a LinearLayout as a button and this is how you can have multiple such buttons.)
By the way, if the xml is a drawable, you can just reference that drawable from all buttons.
UPDATE (yes I do know the above does not answer the question after the question is edited):
I used the same background drawable (a selector) for several buttons. The foreground was text (in fact, a LinearLayout). I'd suggest you try to reuse the same background drawable.
Please note that you can have images even on a text button, there are setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) and setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom).

How can I give a series of buttons with background colors a focus?

I made a layout that is just simply a textview that says "What do you want?", followed by a series of buttons underneath it.
All of the buttons can be clicked/touched, but when I scroll with the trackball, none of them become highlighted. I noticed, however, then when I disable the background colors on the buttons, I can see the orange box that shows that button's focus.
Is there any way I can visibly see the focus while still being able to have a background color on the buttons?
EDIT: Found the solution! This helped A LOT. Standard Android Button with a different color
Create a "selector" resource in your res/drawable. It can look something like this:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="false"
android:state_pressed="false"
android:drawable="#color/white" />
<item
android:state_pressed="true"
android:drawable="#color/orange" />
<item
android:state_selected="true"
android:state_pressed="false"
android:drawable="#color/blue" />
</selector>
Then set the background of your button to be:
android:background="#drawable/your_selector"
Rather than applying a simple background color to buttons, try applying a ColorStateList instead.
To do so, define a new XML file at
/res/color/buttonstate.xml
and use code such as the following:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="# FOCUSED COLOR HERE"
android:state_focused="true" />
<item android:drawable="# DEFAULT COLOR HERE" />
</selector>
Notes:
You can definitely add more colors for more states, such as pressed, enabled, and certain other factors.
In the layout or code just reference R.color.buttonstate or #color/buttonstate (the XML's filename).
Make sure the default color is last. This is because it goes down the list and finds the first item that has all of the states the same as it. If you don't provide android:state_focused="false" for the default item and put it first, it will always display.
You can do a similar thing with drawables and
nine-patch drawables to make your own custom button styles.
Rather than just change the background color, consider using a 9-patch style. This is more work to begin, but you'll have much more control over your app's appearance.
Modify your Button layout to look something like this (the style line is the kicker):
<Button
style="#style/PushButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Your styles.xml resource file then should contain a style similar to this:
<style name="PushButton">
<item name="android:background">#drawable/btn</item>
</style>
Then the btn.xml (put in in res/drawable) contents should look something like this:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/btn_pressed"
android:state_pressed="true" />
<item android:drawable="#drawable/btn_focused"
android:state_pressed="false"
android:state_focused="true" />
<item android:drawable="#drawable/btn_default"
android:state_focused="false"
android:state_pressed="false" />
You would then use some image editor to create files named btn_pressed.9.png, btn_focused.9.png, and btn_default.9.png. Drop these files in your res/drawable.
A good starting point is the Google IO app (I lifted the code examples from it). Just grab the png files and modify them to match your desired style.
Keep in mind you can put all sorts of stuff in the style now, like text size, height and width.

Android Set ImageButton as Toggle

How can I have an imagebutton stay in the 'pressed' state when it is clicked? Basically I just want the background to be the depressed background, but I can't figure out how to set it. At the moment, I've just copied the selected button background into my res folder, but when I set it as the background, it becomes blurry (since the original image is bigger than the button itself).
Normal Background:
alt text http://img707.imageshack.us/img707/9199/ss20100426163452.png
What I'm getting:
alt text http://img707.imageshack.us/img707/912/ss20100426163357.png
alt text http://img3.imageshack.us/img3/8304/ss20100426163623.png
Also I don't believe I can actually use this method considering the many different UI layouts. The button should stay pressed as per the UI the user is using.
There are a few ways of doing this:
First, you can simply use an ImageButton, and manually toggle its image drawable on click in Java. This is what the stock Music player on Android does for the shuffle button, for example. Although you won't have control over the button background in its checked state, you'll be able to swap out the image, which may be favorable from an Android UI-consistency perspective.
Another option is to use a complex set of drawables and nine-patches to get an image inside a ToggleButton, with the option of changing the background and/or the image resource upon toggle. That's the option I'll show below. But remember, be cautious about UI consistency before doing this.
res/layout/foo.xml
...
<ToggleButton
android:textOn="" android:textOff=""
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/shuffle_button" />
...
res/drawable/shuffle_button.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- use "#android:drawable/btn_default" to keep consistent with system -->
<item android:drawable="#drawable/toggle_button_background" />
<item android:drawable="#drawable/shuffle_button_image" />
</layer-list>
res/drawable/toggle_button_background.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- checked state -->
<item android:state_pressed="false" android:state_checked="true"
android:drawable="#drawable/btn_default_checked" />
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="#drawable/btn_default_normal_disable" />
<item android:state_pressed="true"
android:drawable="#drawable/btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="#drawable/btn_default_selected" />
<item android:state_enabled="true"
android:drawable="#drawable/btn_default_normal" />
<item android:state_focused="true"
android:drawable="#drawable/btn_default_normal_disable_focused" />
<item android:drawable="#drawable/btn_default_normal_disable" />
</selector>
res/drawable/shuffle_button_image.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/ic_mp_shuffle_on_btn" android:state_checked="true" />
<item android:drawable="#drawable/ic_mp_shuffle_off_btn" />
</selector>
Image files
btn_default_<state>.9.png can be found in frameworks/base.git
under
core/res/res/drawable-hdpi
and
core/res/res/drawable-mdpi (also ldpi).
WARNING: if you use these, your app will look inconsistent on devices with customized OS UIs (i.e. HTC's Sense UI).
ic_mp_shuffle_<state>_btn.9.png need to be nine-patches, so that the image gets centered and not stretched to fit the button. Below are example hdpi versions of the icon:
res/drawable-(h|m|ldpi)/ic_mp_shuffle_(on|off)_btn.9.png
Final Note: Remember to be consistent with the system UI when possible, and be mindful of the fact that your app may run on devices with customized versions of the OS that have different graphics for UI elements like buttons. An example of this is HTC Sense, which has green buttons in place of the grey/orange/yellow ones in stock Android. So, if you end up copying the btn_default_... PNG files from the open source repository to create a toggle-able button background, you'll break consistency on those devices.

Categories

Resources