StateListDrawable Drawable增加多个状态

本文深入解析StateListDrawable在Android中的应用,阐述如何通过定义不同状态的Drawable对象实现UI组件外观的动态变化,包括正常、选中、异常和特定状态下的表现形式。

StateListDrawable 用于组织多个 Drawable 对象。当使用 StateListDrawable 作为目标组件的背景、前景图片时,StateListDrawable 对象所显示的 Drawable 对象会随目标组件的状态的改变而自动切换。

定义 StateListDrawable 对象的 XML 文件的根元素为 ,该元素可以包含多个 元素,该元素可以指定如下属性:

StateListDrawable 的 元素所支持的状态如下所示:

属性值含义
android:state_active是否激活
android:state_checkable是否可勾选
android:state_checked是否已勾选
android:state_enabled是否可用
android:state_first是否处于开始状态
android:state_focused是否已获得焦点
android:state_last是否处于结束状态
android:state_middle是否处于中间状态
android:state_pressed是否按下
android:state_selected是否选中
android:state_window_focused是否窗口已获得焦点

通常代码中使用两种状态:

private static final int[] STATE_NORMAL = {-android.R.attr.state_selected};//-代表此属性为false
private static final int[] STATE_SELECTED = {android.R.attr.state_selected};

private int mNormalId = R.drawable.edit_round_stroke_gray_shape;
private int mSelectId = R.drawable.edit_round_stroke_normal_shape;

StateListDrawable drawable = new StateListDrawable();

Drawable normalDraw = ContextCompat.getDrawable(getContext(), mNormalId);
normalDraw.setBounds(0,0,width,width);
drawable.addState(STATE_NORMAL,normalDraw);

Drawable selectDraw = ContextCompat.getDrawable(getContext(), mSelectId);
selectDraw.setBounds(0,0,width,width);
drawable.addState(STATE_SELECTED,selectDraw);

然而有时候我们需要使用两种以上的状态,我们会想当然的认为那就增加表格中的状态呗:

private static final int[] STATE_NORMAL = {-android.R.attr.state_selected};
private static final int[] STATE_SELECTED = {-android.R.attr.state_selected};
private static final int[] STATE_EXCEPTION = {-android.R.attr.state_checkable};
private static final int[] STATE_RIGHT = {android.R.attr.state_checkable};
 
private int mNormalId = R.drawable.edit_round_stroke_gray_shape;
private int mSelectId = R.drawable.edit_round_stroke_gray_shape;
private int mExceptionId = R.drawable.edit_round_stroke_gray_shape_exception;
private int mRightId = R.drawable.edit_round_stroke_gray_shape_right;

 StateListDrawable drawable = new StateListDrawable();

 Drawable normalDraw = ContextCompat.getDrawable(getContext(), mNormalId);
 normalDraw.setBounds(0,0,width,width);
 drawable.addState(STATE_NORMAL,normalDraw);

 Drawable selectDraw = ContextCompat.getDrawable(getContext(), mSelectId);
 selectDraw.setBounds(0,0,width,width);
 drawable.addState(STATE_SELECTED,selectDraw);

 Drawable exceptionDraw = ContextCompat.getDrawable(getContext(), mExceptionId);
 exceptionDraw.setBounds(0,0,width,width);
 drawable.addState(STATE_EXCEPTION,exceptionDraw);

 Drawable rightDraw = ContextCompat.getDrawable(getContext(), mRightId);
 rightDraw.setBounds(0,0,width,width);
 drawable.addState(STATE_RIGHT,rightDraw);

然而结果并不如想象美好。
当我drawable.setState(STATE_RIGHT)时,并没有成功改变状态。
有可能的原因:有些状态互斥。

后来发现addState()的第一个参数是一个数组,所以我们可以设置组合状态:

 private static final int[] STATE_NORMAL = {-android.R.attr.state_selected};
 private static final int[] STATE_SELECTED = {-android.R.attr.state_selected};
 private static final int[] STATE_EXCEPTION = {-android.R.attr.state_checkable,android.R.attr.state_selected};
 private static final int[] STATE_RIGHT = {android.R.attr.state_checkable,android.R.attr.state_selected};

其他不变,就ok了。
效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在 Android 开发中,复制一个 `Drawable` 对象的新实例并不是一个直接的过程,因为 `Drawable` 是一个抽象类,且其子类可能具有不同的状态和属性。为了正确地复制一个 `Drawable`,通常需要考虑其当前的状态、可变性以及是否支持共享状态。 一种通用的方法是使用 `Drawable` 的 `mutate()` 方法,该方法确保返回的 `Drawable` 是可变的,并且不会与其他 `Drawable` 实例共享状态。以下是一个示例代码,展示了如何创建一个 `Drawable` 的新实例: ```java Drawable originalDrawable = context.getDrawable(R.drawable.your_drawable); Drawable copiedDrawable = originalDrawable.mutate(); ``` 在这个例子中,`mutate()` 方法用于确保返回的 `Drawable` 是独立的,不会与原始 `Drawable` 共享状态。这对于避免意外修改共享的状态非常有用 [^3]。 如果你需要更精细的控制,例如复制特定类型的 `Drawable`(如 `BitmapDrawable` 或 `StateListDrawable`),你可能需要根据具体的子类来实现深拷贝逻辑。例如,对于 `BitmapDrawable`,你可以通过获取其内部的 `Bitmap` 并创建一个新的 `BitmapDrawable` 来实现复制: ```java BitmapDrawable originalBitmapDrawable = (BitmapDrawable) context.getDrawable(R.drawable.your_drawable); Bitmap bitmap = originalBitmapDrawable.getBitmap(); BitmapDrawable copiedBitmapDrawable = new BitmapDrawable(context.getResources(), bitmap); ``` 对于其他类型的 `Drawable`,如 `StateListDrawable`,你可能需要遍历其所有状态并手动复制每个状态对应的 `Drawable`。这通常涉及更多的代码,并且需要处理每个子类的具体细节 [^3]。 ### 注意事项 - **mutate() 方法**:`mutate()` 方法并不总是返回一个新的实例;它可能会返回当前实例,特别是当当前实例已经是不可变的情况下。因此,在调用 `mutate()` 后,最好检查返回值是否为新的实例。 - **资源管理**:在复制 `Drawable` 时,尤其是包含大量资源(如 `Bitmap`)的 `Drawable`,需要注意内存管理和性能优化。 - **状态保持**:如果 `Drawable` 包含了特定的状态(如动画状态),则简单的复制可能无法保留这些状态。在这种情况下,你需要手动处理状态的复制或重置。 通过上述方法,你可以在 Android 开发中有效地复制一个 `Drawable` 对象的新实例,并确保其状态独立于原始 `Drawable`。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值