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使用优先级队列实现哈夫曼编码
思路: 构建小根堆 根据小根堆实现哈夫曼树 根据哈夫曼树对数据进行编码 代码实现如下: /** * @Author: DaleyZou * @Description: 使用java实现一个哈夫曼编码的 ...
- Smartforms 设置纸张打印格式
在sap做一个打印报表,要先设置一个纸张打印格式,下面以工厂中常用来打印的针孔纸为例,在sap设置该纸张的打印格式,以用于报表: 1.运行事务代码SPAD:选择工具栏上的[完全管理]按钮——>选 ...
- Hibernate进阶学习4
Hibernate进阶学习4 深入学习hibernate的查询语句 测试HQL查询 package com.hibernate.test; import com.hibernate.domain.Cu ...
- 爬虫学习(十一)——bs4基础学习
ba4的介绍: bs4是第三方提供的库,可以将网页生成一个对象,这个网页对象有一些函数和属性,可以快捷的获取网页中的内容和标签 lxml的介绍 lxml是一个文件的解释器,python自带的解释器是: ...
- MySQL 5.7传统复制到GTID在线切换(一主一从)
Preface Classic replication is commonly used in previous version of MySQL.It's really tough in ...
- RedHat6.4安装图形行化界面
1.1 打开电源进入RedHat shell命令行界面 1.2 查看系统镜像包括的所有软件包组信息 [root@zhongyi-test ~]# yum grouplist Loaded ...
- proteus中蜂鸣器不响的原因
本文参考自https://blog.csdn.net/gin_love/article/details/51168369 此网站.在用proteus仿真报警电路时,发现蜂鸣器不响.后在网上找了 ...
- 1 Django初探
1.理解MTV request 向服务器请求 response发送数据给用户 M:数据库取出数据 T: 模板渲染 V:渲染好的网页返回给用户 URL找到特定的views 2.创建django项目 (1 ...
- 3714: [PA2014]Kuglarz
3714: [PA2014]Kuglarz 链接 思路: 好题.对于每个点都需要确定它的值,那么一个点可以直接询问[i,i]来确定,或者已经知道了[i,j]和[i+1,j]推出来. 但是可能产生冲突, ...
- HEXO next live2d插件删除问题
title: HEXO next live2d插件删除问题 date: 2018-03-06 13:09:12 updated: tags: [hexo,next,建站,学习,前端技术,疑问] des ...