转载 声明原处 :博客http://pk272205020.blog.163.com/
参考论坛外国android论坛http://www.androidpeople.com/
参考资料:android Button 原理
这几日都是看android SDK原码,想封装一个HERO 效果的UI界面。刚想以为很容易,但越做越难,为有百度,Google求救,但这方面的资料还是不多,这个我也不怪了,可能android 在中国的市场还是刚刚起步。外面的一些网站 android 技术论坛打不开,闷 ...
但我发现http://www.android.com/ 可以打开了,以前要用XX软件先打得开,但里面的developer标签还是俾中国网关封,这个更郁闷... 不讲了,直入正题 android Styel原理
刚刚开始得写时从最简单的Button 入手,下载SDK原码候Button 继续TextView 原码里就三个构造方法....
@RemoteView
public class Button extends TextView {
public Button(Context context) {
this(context, null);
}
public Button(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.buttonStyle);
}
public Button(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}[
默认样式:com.android.internal.R.attr.buttonStyle ,android 的style 太强大, 网上有人说过是 GWT模式, 在校的时候我也用过GWT写过小网页,HTML文件里标签里嵌入GWT标签,通过服务端Java代码生成页面,GWT就讲到这里,有开展过GWT的同志就知道这个也很像android的Layout布局文件,哈哈 我也是认同网上的人说。
知道android 的Style模式后,我们要进一步了解内部的实现,我们要打开 com.android.internal.R.attr.buttonStyle这个对应的XML
< style name="Widget.Button" >
< item name="android:background">@android:drawable/btn_default< /item>
< item name="android:focusable" >true< /item >
< item name="android:clickable" >true< /item >
< item name="android:textSize" >20sp< /item >
< item name="android:textStyle" >normal< /item >
< item name="android:textColor" >@android:color/button_text </item >
< itemname="android:gravity">center_vertical|center_horizontal< /item>
< /style >
这个文件定义了好多style相关的属性,每个属性都好理解,这个backgroud属性难道仅仅是一个drawable图片?如果仅仅是一个图片的化,怎么能够实现button各种状态下表现出不同背景的功能呢?还是来看看这个drawable到底是什么东西。
还是埋头苦干地找出答案
在drwable目录中发现这个btn_default这个文件,还有许多这样的xml文件,看名字可以估到是什么来的
btn_default.xml 内容
< selector xmlns:android="http://schemas.android.com/apk/res/android">
< item android:state_window_focused="false" android:state_enabled="true"
android:drawable="@drawable/btn_default_normal" / >
< item android:state_window_focused="false" android:state_enabled="false"
android:drawable="@drawable/btn_default_normal_disable" / >
< item android:state_pressed="true"
android:drawable="@drawable/btn_default_pressed" / >
< item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/btn_default_selected" / >
< item android:state_enabled="true"
android:drawable="@drawable/btn_default_normal" / >
< item android:state_focused="true"
android:drawable="@drawable/btn_default_normal_disable_focused" / >
< item android:drawable="@drawable/btn_default_normal_disable" / >
< /selector >
在android 中drawable文件是看图片存放的,最普通的就是一个图片。而这里用到的是StateListDrawable。当Android的解析器解析到上面的xml时,会自动转化成一个StateListDrawable类的实例,看看SDK是这样说的
Lets you assign a number of graphic images to a single Drawable and swap out the visible item by a string ID value.
It can be defined in an XML file with the <selector> element. Each state Drawable is defined in a nested <item> element. For more information, see the guide to Drawable Resources.
意思就是通过字符串标识符值ID 分配单个可绘制可切换 的可视图形项
看看核心代码吧:大部多代码删除了
public class StateListDrawable extends DrawableContainer {
/**
* To be proper, we should have a getter for dither (and alpha, etc.)
* so that proxy classes like this can save/restore their delegates'
* values, but we don't have getters. Since we do have setters
* (e.g. setDither), which this proxy forwards on, we have to have some
* default/initial setting.
*
* The initial setting for dither is now true, since it almost always seems
* to improve the quality at negligible cost.
*/
private static final boolean DEFAULT_DITHER = true;
private final StateListState mStateListState;
private boolean mMutated;
public StateListDrawable() {
this(null, null);
}
/**
* Add a new image/string ID to the set of images.
*
* @param stateSet - An array of resource Ids to associate with the image.
* Switch to this image by calling setState().
* @param drawable -The image to show.
*/
public void addState(int[] stateSet, Drawable drawable) {
if (drawable != null) {
mStateListState.addStateSet(stateSet, drawable);
// in case the new state matches our current state...
onStateChange(getState());
}
}
@Override
public boolean isStateful() {
return true;
}
@Override
protected boolean onStateChange(int[] stateSet) {
int idx = mStateListState.indexOfStateSet(stateSet);
if (idx < 0) {
idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
}
if (selectDrawable(idx)) {
return true;
}
return super.onStateChange(stateSet);
}
/**
* Gets the state set at an index.
*
* @param index The index of the state set.
* @return The state set at the index.
* @hide pending API council
* @see #getStateCount()
* @see #getStateDrawable(int)
*/
public int[] getStateSet(int index) {
return mStateListState.mStateSets[index];
}
static final class StateListState extends DrawableContainerState {
private int[][] mStateSets;
StateListState(StateListState orig, StateListDrawable owner, Resources res) {
super(orig, owner, res);
if (orig != null) {
mStateSets = orig.mStateSets;
} else {
mStateSets = new int[getChildren().length][];
}
}
int addStateSet(int[] stateSet, Drawable drawable) {
final int pos = addChild(drawable);
mStateSets[pos] = stateSet;
return pos;
}
}
private StateListDrawable(StateListState state, Resources res) {
StateListState as = new StateListState(state, this, res);
mStateListState = as;
setConstantState(as);
onStateChange(getState());
}
}
xml中每一个Item就对应一种状态,而每一个有state_的属性就是描述状态,drawable则是真正的drawable图片。当把这个实例付给View作为Background的时候,View会根据不同的state来切换不同状态的图片,从而实现了Press等诸多效果。简单看一下View中有关状态切换的代码吧:
/**
* The order here is very important to {@link #getDrawableState()}
*/
private static final int[][] VIEW_STATE_SETS = {
EMPTY_STATE_SET, // 0 0 0 0 0
WINDOW_FOCUSED_STATE_SET, // 0 0 0 0 1
SELECTED_STATE_SET, // 0 0 0 1 0
SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 0 0 1 1
FOCUSED_STATE_SET, // 0 0 1 0 0
FOCUSED_WINDOW_FOCUSED_STATE_SET, // 0 0 1 0 1
FOCUSED_SELECTED_STATE_SET, // 0 0 1 1 0
FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 0 1 1 1
ENABLED_STATE_SET, // 0 1 0 0 0
ENABLED_WINDOW_FOCUSED_STATE_SET, // 0 1 0 0 1
ENABLED_SELECTED_STATE_SET, // 0 1 0 1 0
ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 1 0 1 1
ENABLED_FOCUSED_STATE_SET, // 0 1 1 0 0
ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET, // 0 1 1 0 1
ENABLED_FOCUSED_SELECTED_STATE_SET, // 0 1 1 1 0
ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 0 1 1 1 1
PRESSED_STATE_SET, // 1 0 0 0 0
PRESSED_WINDOW_FOCUSED_STATE_SET, // 1 0 0 0 1
PRESSED_SELECTED_STATE_SET, // 1 0 0 1 0
PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 0 0 1 1
PRESSED_FOCUSED_STATE_SET, // 1 0 1 0 0
PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET, // 1 0 1 0 1
PRESSED_FOCUSED_SELECTED_STATE_SET, // 1 0 1 1 0
PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 0 1 1 1
PRESSED_ENABLED_STATE_SET, // 1 1 0 0 0
PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET, // 1 1 0 0 1
PRESSED_ENABLED_SELECTED_STATE_SET, // 1 1 0 1 0
PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 1 0 1 1
PRESSED_ENABLED_FOCUSED_STATE_SET, // 1 1 1 0 0
PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET, // 1 1 1 0 1
PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET, // 1 1 1 1 0
PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET, // 1 1 1 1 1
};
详细打开View.java 自己看
下面是setBackground方法,红字就是是state切换 ,View 这个类太长了, android2.2 版一共9321行
/**
* Set the background to a given Drawable, or remove the background. If the
* background has padding, this View's padding is set to the background's
* padding. However, when a background is removed, this View's padding isn't
* touched. If setting the padding is desired, please use
* {@link #setPadding(int, int, int, int)}.
*
* @param d The Drawable to use as the background, or null to remove the
* background
*/
public void setBackgroundDrawable(Drawable d) {
boolean requestLayout = false;
mBackgroundResource = 0;
...............
if (d.isStateful()) {
d.setState(getDrawableState());
}
d.setVisible(getVisibility() == VISIBLE, false);
mBGDrawable = d;
...............
mBackgroundSizeChanged = true;
invalidate();
}
setBackgound方法先判断Drawable对象是否支持state切换 如果支持,设置状态就可达到图片切换的效果。
就写到这里
分享到:
相关推荐
山东大学--局部解剖--重点
C语言深度解剖-C语言深度解剖-C语言深度解剖
人体断层解剖学-纵隔断层解剖 人体断层解剖学是研究人体各个部分的解剖结构的学科。人体断层解剖学-纵隔断层解剖是研究人体胸廓内部的解剖结构,特别是纵隔的解剖结构。 纵隔是指人体胸廓内部由胸骨、肋骨、脊椎骨...
压缩包内的文件“一种解剖型髋臼后柱钢板.pdf”很可能提供了这种特殊钢板的设计原理、使用方法、临床应用、材料特性以及手术操作指南等详细信息。 在医学领域,解剖型髋臼后柱钢板的设计通常是为了更好地适应人体...
本文将从生态环境的角度对进程上下文进行解剖,以便更好地理解进程的设计原则。 #### 二、CI的定义与特性 在本文中,CI(Cell Individual)被定义为构成更大系统的基础组件,相当于细胞在生物体中的作用。CI作为...
护理-专接本人体解剖学试题(卷)与答案解析.doc
【颈部断层解剖】是医学领域中对人体颈部结构进行深入理解的重要研究方法,它通过一系列的横断面图像,揭示颈部的层次结构和器官分布。在这个【人体断层解剖学-颈部断层解剖.ppt】中,主要探讨了以下几个关键知识点...
电信设备-小动物解剖实验托盘.zip
在医学教育领域,解剖学是一门至关重要的基础课程,它为医学生提供了对人体结构的深入理解。"行业文档-设计装置-医学院解剖课教学使用的操作箱.zip" 是一个针对医学院解剖教学设计的资源包,其中包含了“医学院解剖...
医学临床讲义资料-神经系统解剖学知识.pdf
人体解剖学-《人体解剖学》模拟考试题(四)(精选试题).doc
人体解剖学-《人体解剖学》模拟考试题(六)(精选试题).doc
人体解剖学-《人体解剖学》模拟考试题(十)(精选试题).doc
人体解剖学-《人体解剖学》模拟考试题(五)(精选试题).doc
人体解剖学-《人体解剖学》模拟考试题(九)(精选试题).doc
人体解剖学-《人体解剖学》模拟考试题(八)(精选试题).doc
人体解剖学-《人体解剖学》模拟考试题(一)(精选试题).doc
《人体断层解剖学-头部断层解剖》是一份深入探讨人体头部,特别是颞骨与耳部结构的解剖学资料。这份PPT详细展示了颞骨与耳的形态结构,以及不同层面的横断面解剖,帮助学习者理解和掌握这个复杂区域的精细构造。 ...
医疗设备应用培训-冠状窦解剖与冠状静脉造影.pdf
标题中的“行业分类-设备装置-一种解剖重建颅骨补片及其快速制作方法”表明了这个压缩包的内容主要涉及医疗设备领域,特别是与颅骨修复相关的技术。在这个专题中,我们将深入探讨颅骨补片的解剖重建过程以及其快速...