drawable state系列文章
XML类型的drawable图片的解析处理过程
===============================================
一个state list drawable在根据View的状态来显示不同的图片是非常有用的.例如,我们可以为一个按钮的背景定义一个按下状态和非按下状态的状态图片列表,按钮就会根据不同的状态改变图片.我们也可以通过自定义的图片状态列表使其变得更加的有用。
下面是一个邮件客户端,它分别标识了已读邮件和未读邮件。
上面的列表使用了一个ListView,每个列表项使用了一个RelativeLayout,在这个RelativeLayout中包含有一个ImageView和一个TextView,当显示每项的时候,你可以手工的转换两张图片,并且一次的设置背景颜色。但是通过定义一个自定义状态,你可以更加简单和方便的进行管理。
第一步:声明自定义的状态属性
自定义状态是声明在attrs.xml文件中,这个文件在应用的res/values目录下。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MessageState">
<attr name="state_message_unread" format="boolean"/>
</declare-styleable>
</resources>
第二步:在图片状态列表中使用自定义的状态
在我们的例子中,有两个状态图片列表。
一个是用做背景改变的列表项:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:example="http://schemas.android.com/apk/res/com.charlesharley.example.android.customdrawablestates"
>
<!--
We make the pressed and focused selector items transparent so the ListView's own selector states show through.
-->
<item android:state_pressed="true"
android:drawable="@android:color/transparent"
/>
<item android:state_focused="true"
android:drawable="@android:color/transparent"
/>
<item example:state_message_unread="true"
android:drawable="@color/message_list_item_background_unread"
/>
</selector>
一个是消息状态图标改变的列表项:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:example="http://schemas.android.com/apk/res/com.charlesharley.example.android.customdrawablestates"
android:constantSize="true"
>
<item example:state_message_unread="true"
android:drawable="@drawable/message_read_status_unread"
/>
<item android:drawable="@drawable/message_read_status_read" />
</selector>
为了能够使用自定义的状态,需要使用应用的包名声明一个新的XML命名空间,并且使用新的命名空间作为自定义状态属性的前缀。
第三步:合入自定义的状态来更新View的drawable状态
每个View都提供了一些现存的可以使用的状态,例如CheckBox有选中状态,通过重写View.onCreateDrawableState() ,自定义View可以注入它自己的状态,然后我们就可以使用这个状态 。
在我们上面的例子中,包含有ImageView和TextView的RelativeLayout实现维持了一个未读状态,它可以设置和更新View的drawable状态,这样我们就可以看到已读和未读两种状态的邮件项。
public class MessageListItemView extends RelativeLayout {
private static final int[] STATE_MESSAGE_UNREAD = {R.attr.state_message_unread};
private boolean messageUnread;
// Constructors, view loading etc...
@Override
protected int[] onCreateDrawableState(int extraSpace) {
// If the message is unread then we merge our custom message unread state into
// the existing drawable state before returning it.
if (messageUnread) {
// We are going to add 1 extra state.
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
mergeDrawableStates(drawableState, STATE_MESSAGE_UNREAD);
return drawableState;
} else {
return super.onCreateDrawableState(extraSpace);
}
}
public void setMessageUnread(boolean messageUnread) {
if (this.messageUnread != messageUnread) {
this.messageUnread = messageUnread;
// Refresh the drawable state so that it includes the message unread
// state if required.
refreshDrawableState();
}
}
}
我们知道,上面只是在MessageListItemView里面添加了自定义的状态,我们改变的只是MessageListItemView的状态,相应的触发了它背景颜色的改变。但是,ImageView包含在它的里面,MessageListItemView的状态是如何改变ImageView的状态的呢?
因为ImageView是我们自定义布局的一个子View,我们可以使用View.setDuplicateParentStateEnabled()告诉它去复制父布局的状态,这样父布局的状态就可以传递给包含了这个自定义状态的子布局中。
具体的代码如下:
View example application on Github
原文链接: