在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中如何为自定义控件增加状态?的更多相关文章

  1. android中正确保存view的状态

    英文原文: http://trickyandroid.com/saving-android-view-state-correctly/ 转载此译文须注明出处. 今天我们聊一聊安卓中保存和恢复view状 ...

  2. Android中activity保存数据和状态在哪个方法实现

    以前只知道在Activity销毁之前,要把数据保存在 onSaveInstanceState(Bundle)方法中,后来学习了别人的微博,学到了很多细节问题,所以整理了一下,希望能帮到大家. 如果看官 ...

  3. Android中StateListDrawable的种类(状态的种类)

    <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="ht ...

  4. android 中如何获取camera当前状态

    /** * 测试当前摄像头能否被使用 * * @return */ public static boolean isCameraCanUse() { boolean canUse = true; Ca ...

  5. android中广播接收SD卡状态

    mReceiver = new BroadcastReceiver() { //add by mengmeng.chen begin public void onReceive(Context con ...

  6. Android中View绘制流程以及invalidate()等相关方法分析

    [原文]http://blog.csdn.net/qinjuning 整个View树的绘图流程是在ViewRoot.java类的performTraversals()函数展开的,该函数做的执行过程可简 ...

  7. Android中View绘制流程以及invalidate()等相关方法分析(转载的文章,出处在正文已表明)

    转载请注明出处:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时 ...

  8. Android中View绘制流程以及invalidate()等相关方法分析(转)

    转自:http://blog.csdn.net/qinjuning 前言: 本文是我读<Android内核剖析>第13章----View工作原理总结而成的,在此膜拜下作者 .同时真挚地向渴 ...

  9. Android开发技巧——自定义控件之增加状态

    Android开发技巧--自定义控件之增加状态 题外话 这篇本该是上周四或上周五写的,无奈太久没写博客,前几段把我的兴头都用完了,就一拖再拖,直到今天.不想把这篇拖到下个月,所以还是先硬着头皮写了. ...

随机推荐

  1. vue面试常被问到的问题整理

    1.Vue的双向数据绑定原理是什么? 答 : vue是采用数据劫持,并且使用发布-订阅者的开发模式.原理是观察者observer通过Object.defineProperty()来劫持到各个属性的ge ...

  2. Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: Pointcut is not well-formed: expecting 'name pattern' at character position 36

    例: <aop:config> <aop:pointcut expression="execution(* com.zsn.Service.Impl.*.*(..))&qu ...

  3. ssm整合-错误

    [Err] 1005 - Can't create table 'imoocdb.ec_article' (errno: 150) 这个错误由外键约束引起的 java.lang.ClassCastEx ...

  4. C#爬虫实践

    忘了什么时候加的,iPad上的人人视频追剧了<我的天才女友>,没事的时候看了下,感觉还不错,进一步了解到原著那不勒斯四部曲,感觉视频进度有些慢,就想找找书看看,一时没找到[PS:购买实体书 ...

  5. 【PHP项目】$_SEVER详解

    $_SERVER['HTTP_ACCEPT_LANGUAGE']//浏览器语言 $_SERVER['REMOTE_ADDR'] //当前用户 IP . $_SERVER['REMOTE_HOST'] ...

  6. cmd中编译java脚本 (2013-05-02-bd 写的日志迁移

    此前提是已经搭建好了jdk的编译环境! 先写一个java脚本如:建立一个HelloWord.java //public : 表示此类是公共的 一个java文件中只能有一个public类 //class ...

  7. 图解HTTP总结(4)——返回结果的HTTP状态码

    HTTP状态码负责表示客户端HTTP请求的返回结果.标记服务器端的处理是否正常.通知出现的错误等工作. 状态码的类别 2XX 成功 200 OK 表示从客户端发来的请求在服务器端被正常处理了. 在响应 ...

  8. 学习python第十一天,函数3 函数的序列化和反序列化

    我们把变量从内存中变成可存储或传输的过程称之为序列化,序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上. 反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unp ...

  9. POJ 1854 贪心(分治)

    Evil Straw Warts Live Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 1144   Accepted:  ...

  10. L2-029 特立独行的幸福 (25 分)

    L2-029 特立独行的幸福 (25 分)   对一个十进制数的各位数字做一次平方和,称作一次迭代.如果一个十进制数能通过若干次迭代得到 1,就称该数为幸福数.1 是一个幸福数.此外,例如 19 经过 ...