Android中如何为自定义控件增加状态?
在android开发中我们常常需要对控件进行相关操作,虽然网上已有很多对控件酷炫的操作,但小编今天给大家分享的纯属实用出发。在查看了一些列安卓教程和文档后,发现了一位大牛分享的非常不错的有关android自定义控件增加状态的文章,分享给大家,学习、参考。
场景
View类是Android UI组件的基础构建模块,主要负责组件的绘制及事件的处理。我们在一些自定义控件的场合,可能需要在一个组件上画些东西,也是通过重写View的onDraw方法,通过其参数的Canvas对象进行绘制。
我们学习<selector/>的时候,就知道了关于一个视图组件会有许多种状态,比如按下(pressed),选择(selected),可用(enabled),正常状态,其他状态等等。View也处理了关于一个组件在不同状态下的显示的绘制逻辑,通常继承自View的组件都有着以上所说的这些状态。但是也有一些状态是View没有提供的,而我们可能正需要它们,所以就需要对状态进行扩展,增加我们的状态,比如增加checked。
这里有一个具体的场景:
这是一个开关按钮,开关状态下背景不同,文字不同,文字旁边的图片也不同。状态我用checked,文字我定义了两个属性:onText以及offText,文字旁边的图片我打算只用一个foreground属性,但需要写一个selector来定义正常状态(未锁)和checked状态(锁定)下的图片。
实现
首先写一个类继承自TextView,因为我打算用TextView的setCompoundDrawables来设定文字旁边的图片。
然后定义属性:
<declare-styleable name="ToggleView">
<attr name="android:foreground"/>
<attr name="pwOnText"/>
<attr name="pwOffText"/>
<attr name="pwColor"/>
<attr name="pwDrawableHeight"/>
</declare-styleable>
读取属性:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ToggleView);
stateListDrawable = (StateListDrawable) a.getDrawable(R.styleable.ToggleView_android_foreground);
colorStateList = a.getColorStateList(R.styleable.ToggleView_pwColor);
offText = a.getString(R.styleable.ToggleView_pwOffText);
onText = a.getString(R.styleable.ToggleView_pwOnText);
drawableHeight = a.getDimensionPixelSize(R.styleable.ToggleView_pwDrawableHeight, 0);
a.recycle();
通过在类中实现Checkable接口,可以完成选中的逻辑,但是画出来的状态却没有更新,所以接下来的实现过程就是本篇的主要内容:
首先定义状态集:
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
然后我们要把状态给加进去。我们需要重写protected int[] onCreateDrawableState(int extraSpace)方法,如下:
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
先调用父类的onCreateDrawableState方法得到状态数组对象drawableState,但是参数extraSpace要加上1,因为我们要往里面增加一个状态。然后判断在代码逻辑中,是否为选中状态,如果是的话,调用mergeDrawableStates(drawableState, CHECKED_STATE_SET)方法把我们的状态值给加进去,最终返回drawableState。
但是我们虽然实现了Checkable接口,在设置状态时却没有触发到这个状态。所以我们需要自己去触发这个状态。
@Override
public void setChecked(boolean checked) {
if (isChecked != checked) {
isChecked = checked;
refreshDrawableState();
}
}
在状态改变时,调用refreshDrawableState()刷新状态。
最后,我们要重写drawableStateChanged()方法,获取到当前状态的drawable,然后绘制出来。
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (stateListDrawable != null) {
int[] myDrawableState = getDrawableState();
stateListDrawable.setState(myDrawableState);
Drawable drawable = stateListDrawable.getCurrent();
if(drawableHeight != 0) {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth() * drawableHeight / drawable.getIntrinsicHeight(), drawableHeight);
} else {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}
if (isChecked) {
setCompoundDrawables(drawable, null, null, null);
} else {
setCompoundDrawables(null, null, drawable, null);
}
}
setText(isChecked ? onText : offText);
}
这部分代码中我需要设定drawable的大小,以及在不同的状态下设置drawable的位置,因此稍微比较复杂一点点,实际上逻辑只需要如下:
获取当前的drawableState状态
对stateListDrawable(带状态的drawable集)设置状态。
获取stateListDrawable的当前状态的drawable
进行你所想要的绘制。
这样就完成了。
总结
从上面可知,增加状态的过程如下:
定义状态数组
重写protected int[] onCreateDrawableState(int extraSpace)
调用refreshDrawableState()
重写protected void drawableStateChanged()
以上就是android自定义控件增加状态的方法,如果你还有更好的实现方法,欢迎补充分享。
相关文章:《如何实现自己的Android MVP框架?》
Android中如何为自定义控件增加状态?的更多相关文章
- android中正确保存view的状态
英文原文: http://trickyandroid.com/saving-android-view-state-correctly/ 转载此译文须注明出处. 今天我们聊一聊安卓中保存和恢复view状 ...
- Android中activity保存数据和状态在哪个方法实现
以前只知道在Activity销毁之前,要把数据保存在 onSaveInstanceState(Bundle)方法中,后来学习了别人的微博,学到了很多细节问题,所以整理了一下,希望能帮到大家. 如果看官 ...
- Android中StateListDrawable的种类(状态的种类)
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="ht ...
- android 中如何获取camera当前状态
/** * 测试当前摄像头能否被使用 * * @return */ public static boolean isCameraCanUse() { boolean canUse = true; Ca ...
- android中广播接收SD卡状态
mReceiver = new BroadcastReceiver() { //add by mengmeng.chen begin public void onReceive(Context con ...
- Android中View绘制流程以及invalidate()等相关方法分析
[原文]http://blog.csdn.net/qinjuning 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简 ...
- Android中View绘制流程以及invalidate()等相关方法分析(转载的文章,出处在正文已表明)
转载请注明出处:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时 ...
- Android中View绘制流程以及invalidate()等相关方法分析(转)
转自:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴 ...
- Android开发技巧——自定义控件之增加状态
Android开发技巧--自定义控件之增加状态 题外话 这篇本该是上周四或上周五写的,无奈太久没写博客,前几段把我的兴头都用完了,就一拖再拖,直到今天.不想把这篇拖到下个月,所以还是先硬着头皮写了. ...
随机推荐
- 《阿里巴巴Java开发手册》阅读笔记
1.抽象类命名使用 Abstract 或 Base 开头: 异常类命名使用 Exception 结尾: 测试类命名以它要测试的类的名称开始,以 Test 结尾. 2.POJO 类中布尔类型的变量,都不 ...
- LOJ#515. 「LibreOJ β Round #2」贪心只能过样例(bitset)
内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: nzhtl1477 提交提交记录统计讨论测试数据 题目描述 一共有 nnn个数,第 iii ...
- Win10上Anaconda环境下python3.6安装和使用pyinstaller
一.安装步骤 1. 电脑是win10,安装的Python3.6 2. 在Scripts文件夹下执行pip install pyinstaller, 安装成功后下载pyinstaller安装包,解压之后 ...
- LeetCode962. 最大宽度坡
问题:最大宽度坡 给定一个整数数组 A,坡是元组 (i, j),其中 i < j 且 A[i] <= A[j].这样的坡的宽度为 j - i. 找出 A 中的坡的最大宽度,如果不存在,返 ...
- iPhone 横屏时默认会放大文字的问题
有人说用 html { text-size-adjust: 100%; }我发现这个并不能解决问题.下面代码可以完美解决. 添加标签:<meta name="viewport" ...
- 中通快递股份有限公司.net高级面试题
中通快递分布式技术开发 gc垃圾回收原理 .net中,托管代码的内存管理是自动的,由GC进行管理,而对于非托管代码,则需要.net手动处理 CLR运行时,内存分为:托管堆和栈,其中栈用于存储值类型 ...
- const用法总结(通俗易懂)
const的意思可以概括为 “一个不能被改变的普通变量” ,使得const在一定程度上提高程序的安全性和可靠性. const的几种情况: 1. const的普通用法 int const size: c ...
- C# 禁止在textBox输入框输入非法字符
首先添加下面代码 //禁止在textBox输入框输入非法字符 private void keypressed(Object o, KeyPressEventArgs e) { if (e.KeyCha ...
- strchr函数的用法
原型: char *strchr(const char *s,char c); #include<string.h> 查找字符串s中首次出现字符c的位置,返回首次出现c的位置的指针,如果s ...
- 7-1 寻找大富翁 PTA 堆排序
7-1 寻找大富翁 (25 分) 胡润研究院的调查显示,截至2017年底,中国个人资产超过1亿元的高净值人群达15万人.假设给出N个人的个人资产值,请快速找出资产排前M位的大富翁. 输入格式: 输入首 ...