注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

东东的博客

江南烟雨,同大家一起分享

 
 
 

日志

 
 

Android button原理  

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

  下载LOFTER 我的照片书  |

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

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


  1. * <p><strong>XML attributes</strong></p> 

  2. * <p>  

  3. * See {@link android.R.styleable#Button Button Attributes},  

  4. * {@link android.R.styleable#TextView TextView Attributes},   

  5. * {@link android.R.styleable#View View Attributes} 

  6. * </p> 

  7. */ 

  8. ublic class Button extends TextView { 

  9.    public Button(Context context) { 

  10.        this(context, null); 

  11.    } 

  12.  

  13.    public Button(Context context, AttributeSet attrs) { 

  14.        this(context, attrs, com.android.internal.R.attr.buttonStyle); 

  15.    } 

  16.  

  17.    public Button(Context context, AttributeSet attrs, int defStyle) { 

  18.        super(context, attrs, defStyle); 

  19.    } 


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

com.android.internal.R.attr.buttonStyle

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


  1. <style name="Widget.Button"> 

  2.     <item name="android:background">@android:drawable/btn_default</item> 

  3.     <item name="android:focusable">true</item> 

  4.     <item name="android:clickable">true</item> 

  5.     <item name="android:textSize">20sp</item> 

  6.     <item name="android:textStyle">normal</item> 

  7.     <item name="android:textColor">@android:color/button_text</item> 

  8.     <item name="android:gravity">center_vertical|center_horizontal</item> 

  9. </style> 


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

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


  1. <selector xmlns:android="http://schemas.android.com/apk/res/android"> 

  2. ?    <item android:state_window_focused="false" android:state_enabled="true" 

  3.         android:drawable="@drawable/btn_default_normal" /> 

  4. ?    <item android:state_window_focused="false" android:state_enabled="false" 

  5.         android:drawable="@drawable/btn_default_normal_disable" /> 

  6.     <item android:state_pressed="true"  

  7.         android:drawable="@drawable/btn_default_pressed" /> 

  8.     <item android:state_focused="true" android:state_enabled="true" 

  9.         android:drawable="@drawable/btn_default_selected" /> 

  10.     <item android:state_enabled="true" 

  11.         android:drawable="@drawable/btn_default_normal" /> 

  12.     <item android: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. public class StateListDrawable extends DrawableContainer { 

  2.     public StateListDrawable() 

  3.     { 

  4.         this(null); 

  5.     } 

  6.  

  7.     /** 

  8.      * Add a new image/string ID to the set of images. 

  9.      * @param stateSet - An array of resource Ids to associate with the image. 

  10.      * Switch to this image by calling setState().  

  11.      * @param drawable -The image to show. 

  12.      */ 

  13.     public void addState(int[] stateSet, Drawable drawable) { 

  14.         if (drawable != null) { 

  15.             mStateListState.addStateSet(stateSet, drawable); 

  16.             // in case the new state matches our current state... 

  17.             onStateChange(getState()); 

  18.         } 

  19.     } 

  20. ... 



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

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

各种View的状态列表:


  1. /** 

  2.  * The order here is very important to {@link #getDrawableState()} 

  3.  */ 

  4. private static final int[][] VIEW_STATE_SETS = { 

  5.     EMPTY_STATE_SET,                                           // 0 0 0 0 0 

  6.     WINDOW_FOCUSED_STATE_SET,                                  // 0 0 0 0 1 

  7.     SELECTED_STATE_SET,                                        // 0 0 0 1 0 

  8.     SELECTED_WINDOW_FOCUSED_STATE_SET,                         // 0 0 0 1 1 

  9.     FOCUSED_STATE_SET,                                         // 0 0 1 0 0 

  10.     FOCUSED_WINDOW_FOCUSED_STATE_SET,                          // 0 0 1 0 1 

  11.     FOCUSED_SELECTED_STATE_SET,                                // 0 0 1 1 0 

  12.     FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,                 // 0 0 1 1 1 

  13.     ENABLED_STATE_SET,                                         // 0 1 0 0 0 

  14.     ENABLED_WINDOW_FOCUSED_STATE_SET,                          // 0 1 0 0 1 

  15.     ENABLED_SELECTED_STATE_SET,                                // 0 1 0 1 0 

  16.     ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET,                 // 0 1 0 1 1 

  17.     ENABLED_FOCUSED_STATE_SET,                                 // 0 1 1 0 0 

  18.     ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET,                  // 0 1 1 0 1 

  19.     ENABLED_FOCUSED_SELECTED_STATE_SET,                        // 0 1 1 1 0 

  20.     ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,         // 0 1 1 1 1 

  21.     PRESSED_STATE_SET,                                         // 1 0 0 0 0 

  22.     PRESSED_WINDOW_FOCUSED_STATE_SET,                          // 1 0 0 0 1 

  23.     PRESSED_SELECTED_STATE_SET,                                // 1 0 0 1 0 

  24.     PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET,                 // 1 0 0 1 1 

  25.     PRESSED_FOCUSED_STATE_SET,                                 // 1 0 1 0 0 

  26.     PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET,                  // 1 0 1 0 1 

  27.     PRESSED_FOCUSED_SELECTED_STATE_SET,                        // 1 0 1 1 0 

  28.     PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET,         // 1 0 1 1 1 

  29.     PRESSED_ENABLED_STATE_SET,                                 // 1 1 0 0 0 

  30.     PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET,                  // 1 1 0 0 1 

  31.     PRESSED_ENABLED_SELECTED_STATE_SET,                        // 1 1 0 1 0 

  32.     PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET,         // 1 1 0 1 1 

  33.     PRESSED_ENABLED_FOCUSED_STATE_SET,                         // 1 1 1 0 0 

  34.     PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET,          // 1 1 1 0 1 

  35.     PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET,                // 1 1 1 1 0 

  36.     PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 1 1 1 1 

  37. }; 


设置background的代码:


  1. /** 

  2.  * Set the background to a given Drawable, or remove the background. If the 

  3.  * background has padding, this View's padding is set to the background's 

  4.  * padding. However, when a background is removed, this View's padding isn't 

  5.  * touched. If setting the padding is desired, please use 

  6.  * {@link #setPadding(int, int, int, int)}. 

  7.  *  

  8.  * @param d The Drawable to use as the background, or null to remove the 

  9.  *        background 

  10.  */ 

  11. public void setBackgroundDrawable(Drawable d) { 

  12.          

  13.         ... 

  14.  

  15.         if (d.isStateful()) { 

  16.             d.setState(getDrawableState()); 

  17.         } 

  18.         d.setVisible(getVisibility() == VISIBLE, false); 

  19.         mBGDrawable = d; 

  20.          

  21.     ... 

  22.  

  23.     invalidate(); 



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

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


转自:http://xxw8393.blog.163.com/blog/static/37256834200973131653574/

  评论这张
 
阅读(4030)| 评论(2)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017