原文地址:

http://li53262182.blog.163.com/blog/static/12839338720091113382422/


Android button原理

2009-12-01 15:38:02|分类: android相关 |字号订阅

在Android中Button是非常常用的一个View控件,原本以为Button实现的代码肯定很多,但是看了原来着实吃了一惊.Button的源码几乎仅仅对继承的TextView类做了一个小小的修改,仅仅是加了一个Style. 一个Style就能够实现Button的显示效果样式么?Android的Style机制真的很强大.

首先来看一下ButtonView的实现代码:

        
  1. *<p><strong>XMLattributes</strong></p>
  2. *<p>
  3. *See{@linkandroid.R.styleable#ButtonButtonAttributes},
  4. *{@linkandroid.R.styleable#TextViewTextViewAttributes},
  5. *{@linkandroid.R.styleable#ViewViewAttributes}
  6. *</p>
  7. */
  8. ublicclassButtonextendsTextView{
  9. publicButton(Contextcontext){
  10. this(context,null);
  11. }
  12. publicButton(Contextcontext,AttributeSetattrs){
  13. this(context,attrs,com.android.internal.R.attr.buttonStyle);
  14. }
  15. publicButton(Contextcontext,AttributeSetattrs,intdefStyle){
  16. super(context,attrs,defStyle);
  17. }

可以看到,Button继承了TextView之后,仅仅是添加了一个默认的Style —

com.android.internal.R.attr.buttonStyle

我们知道,button其实在TextView的基础之上增加了按钮的背景效果以及按钮按下去的press效果。这么一个Style文件可以搞定这件事情么?顺着这个style找下去,在Android的源码中找到style.xml,并找到相关的定义:

        
  1. <stylename="Widget.Button">
  2. <itemname="android:background">@android:drawable/btn_default</item>
  3. <itemname="android:focusable">true</item>
  4. <itemname="android:clickable">true</item>
  5. <itemname="android:textSize">20sp</item>
  6. <itemname="android:textStyle">normal</item>
  7. <itemname="android:textColor">@android:color/button_text</item>
  8. <itemname="android:gravity">center_vertical|center_horizontal</item>
  9. </style>

这里定义了好多style相关的属性,其他的属性都好理解,这个backgroud属性难道仅仅是一个drawable图片?如果仅仅是一个图片的化,怎么能够实现button各种状态下表现出不同背景的功能呢?还是来看看这个drawable到底是什么东西。

到drwable目录中发现这个btn_default原来也是一个xml文件,内容如下:

        
  1. <selectorxmlns:android="http://schemas.android.com/apk/res/android">
  2. ?<itemandroid:state_window_focused="false"android:state_enabled="true"
  3. android:drawable="@drawable/btn_default_normal"/>
  4. ?<itemandroid:state_window_focused="false"android:state_enabled="false"
  5. android:drawable="@drawable/btn_default_normal_disable"/>
  6. <itemandroid:state_pressed="true"
  7. android:drawable="@drawable/btn_default_pressed"/>
  8. <itemandroid:state_focused="true"android:state_enabled="true"
  9. android:drawable="@drawable/btn_default_selected"/>
  10. <itemandroid:state_enabled="true"
  11. android:drawable="@drawable/btn_default_normal"/>
  12. <itemandroid:state_focused="true"
  13. android:drawable="@drawable/btn_default_normal_disable_focused"/>
  14. <item
  15. android:drawable="@drawable/btn_default_normal_disable"/>
  16. </selector>

其实drawable在Android中有很多种,最普通的就是一个图片。而这里用到的是StateListDrawable。当Android的解析器解析到上面的xml时,会自动转化成一个StateListDrawable类的实例。这个类的一些核心代码如下:

        
  1. publicclassStateListDrawableextendsDrawableContainer{
  2. publicStateListDrawable()
  3. {
  4. this(null);
  5. }
  6. /**
  7. *Addanewimage/stringIDtothesetofimages.
  8. *@paramstateSet-AnarrayofresourceIdstoassociatewiththeimage.
  9. *SwitchtothisimagebycallingsetState().
  10. *@paramdrawable-Theimagetoshow.
  11. */
  12. publicvoidaddState(int[]stateSet,Drawabledrawable){
  13. if(drawable!=null){
  14. mStateListState.addStateSet(stateSet,drawable);
  15. //incasethenewstatematchesourcurrentstate...
  16. onStateChange(getState());
  17. }
  18. }
  19. ...
  20. }

xml里面每一个Item就对应一种状态,而每一个有state_的属性就是一个状态的描述,drawable则是真正的drawable图片(这个其实也可以是其他类型的Drawable实例)。

当把这个实例付给View作为Background的时候,View会根据不同的state来切换不同状态的图片,从而实现了Press等诸多效果。简单看一下View中有关状态切换的代码如下:

各种View的状态列表:

        
  1. /**
  2. *Theorderhereisveryimportantto{@link#getDrawableState()}
  3. */
  4. privatestaticfinalint[][]VIEW_STATE_SETS={
  5. EMPTY_STATE_SET,//00000
  6. WINDOW_FOCUSED_STATE_SET,//00001
  7. SELECTED_STATE_SET,//00010
  8. SELECTED_WINDOW_FOCUSED_STATE_SET,//00011
  9. FOCUSED_STATE_SET,//00100
  10. FOCUSED_WINDOW_FOCUSED_STATE_SET,//00101
  11. FOCUSED_SELECTED_STATE_SET,//00110
  12. FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,//00111
  13. ENABLED_STATE_SET,//01000
  14. ENABLED_WINDOW_FOCUSED_STATE_SET,//01001
  15. ENABLED_SELECTED_STATE_SET,//01010
  16. ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET,//01011
  17. ENABLED_FOCUSED_STATE_SET,//01100
  18. ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET,//01101
  19. ENABLED_FOCUSED_SELECTED_STATE_SET,//01110
  20. ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,//01111
  21. PRESSED_STATE_SET,//10000
  22. PRESSED_WINDOW_FOCUSED_STATE_SET,//10001
  23. PRESSED_SELECTED_STATE_SET,//10010
  24. PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET,//10011
  25. PRESSED_FOCUSED_STATE_SET,//10100
  26. PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET,//10101
  27. PRESSED_FOCUSED_SELECTED_STATE_SET,//10110
  28. PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,//10111
  29. PRESSED_ENABLED_STATE_SET,//11000
  30. PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET,//11001
  31. PRESSED_ENABLED_SELECTED_STATE_SET,//11010
  32. PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET,//11011
  33. PRESSED_ENABLED_FOCUSED_STATE_SET,//11100
  34. PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET,//11101
  35. PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET,//11110
  36. PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,//11111
  37. };

设置background的代码:

        
  1. /**
  2. *SetthebackgroundtoagivenDrawable,orremovethebackground.Ifthe
  3. *backgroundhaspadding,thisView'spaddingissettothebackground's
  4. *padding.However,whenabackgroundisremoved,thisView'spaddingisn't
  5. *touched.Ifsettingthepaddingisdesired,pleaseuse
  6. *{@link#setPadding(int,int,int,int)}.
  7. *
  8. *@paramdTheDrawabletouseasthebackground,ornulltoremovethe
  9. *background
  10. */
  11. publicvoidsetBackgroundDrawable(Drawabled){
  12. ...
  13. if(d.isStateful()){
  14. d.setState(getDrawableState());
  15. }
  16. d.setVisible(getVisibility()==VISIBLE,false);
  17. mBGDrawable=d;
  18. ...
  19. invalidate();
  20. }

红色的部分就是首先判断这个Drawable对象是否支持state切换,当然我们这里的drawable是支持的。然后设置状态,达到切换图片的效果。

所以,以后作一些图片需要根据状态切换不同的效果可以用这个方法啦。。。





更多相关文章

  1. Android各种访问权限Permission详解
  2. android学习——GridView实现主界面布局
  3. Android(安卓)ImageView图片自适应
  4. Android实现列表单选和多选,ListView+CheckedTextView
  5. android每日一问1【2011-09-08】
  6. Android(安卓)切换主题 (二)
  7. Android多媒体学习一:Android中Image的简单实例。
  8. 【阿里云镜像】切换阿里巴巴开源镜像站镜像——Fedora镜像
  9. 【阿里云镜像】切换阿里巴巴开源镜像站镜像——Debian镜像

随机推荐

  1. Android(安卓)WebView 上传文件支持全解
  2. Android默认系统声音/大小修改及配置
  3. Android 使用基于位置的服务(二)
  4. 内存优化之其他优化(容器数据遍历方案,arra
  5. Android(安卓)m6.0权限问题调用封装utils
  6. android的apk文件的xml提取
  7. Android底部tab与标题栏相结合
  8. 你还在把Java当成Android官方开发语言吗?K
  9. Android中的帧动画与补间动画的使用
  10. Android的全局通知机制