自定义组件使用总结
2016-04-22 22:39
344 查看
一 概述
自定义组件有三种方式:1. 继承现有组件,拓展其功能;
2. 组合现有控件,实现模板化;
3. 继承View,重写onDraw()方法,进行重绘;继承ViewGroup,重写相关方法,实现布局。
二 继承现有组件,拓展其功能
项目位置:E:\code\CustomViews\StudyTextView 以及 E:\code\CustomViews\StudyTextView0运行效果:StudyTextView 通过点击自定义组件RotateTextView,实现其文字内容的旋转
StudyTextView0 实现自定义组件PaintDoubleWordsTextView,使其中的文字可随手指移动
总结:
以上两个自定义组件的实现原理均为继承现有组件,并在现有组件的基础上进行功能拓展。
具体而言,步骤如下:
1. 根据需要实现的功能选择所要拓展的组件;
2. 自定义类继承所要拓展的组件,这时,有以下几个重要的方法需要重写或使用:
重写:
构造方法 – 如果要在XML文件中直接使用自定义组件,需要实现具有两个参数的构造方法。这两个参数分别为:Context 与 AttributeSet。
在构造方法中,主要实现获取XML布局文件中写入的自定义属性的值。
在这之前,需要在res/values目录下定义attrs.xml文件,该文件中定义了自定义组件支持的自定义属性。具体写法为:在resources标签下加入declare-styleable标签,并给其一个标签名,一般选择自定义类名作为标签名;然后,在后面自定义属性,以标签attr包裹,内容包括自定义属性名name与自定义属性的类型format。形式如下所示:
<resources> <declare-styleable name="一般为自定义控件类名"> <attr name="自定义属性名" format=""> <attr name="自定义属性名" format=""> ... ... </declare-styleable> </resources>
这就定义了自定义控件的自定义属性,之后就可以在XML布局文件中使用这些自定义属性了。
使用的时候,要在xml文件中写入xmlns,即xml命名空间,形式为:
xmlns:custom=”http://schemas.android.com/apk/res-auto”
或:
xmlns:custom=”http://schemas.android.com/apk/manifest中的package名”
之后就可以“custom:自定义属性名”来使用自定义属性了。
在构造方法中,通过操作TypedArray来获取自定义属性内容,代码如下:
TypedArray options = context.obtainStyledAttributes(attrs, R.styleable.PaintDoubleWordsTextView, 0, 0); int numOfOptions = options.getIndexCount(); for (int i = 0; i < numOfOptions; ++i) { int index = options.getIndex(i); switch (i) { case R.styleable.PaintDoubleWordsTextView_word0 : word0 = options.getString(index); break; case R.styleable.PaintDoubleWordsTextView_word0Size : word0Size = options.getInt(index, DEFAULT_TEXT_SIZE); break; case R.styleable.PaintDoubleWordsTextView_word1 : word1 = options.getString(index); break; case R.styleable.PaintDoubleWordsTextView_word1Size : word1Size = options.getInt(index, DEFAULT_TEXT_SIZE); break; } } options.recycle(); // 勿忘
onDraw()– 在该方法中绘制需要显示的内容
onDraw()方法的参数是一个Canvas对象,通过该对象即可实现自定义组件的内容绘制。
使用:
invalidate()– 导致onDraw()被调用,刷新View
requestLayout()– 当前View的布局失效时就需要进行调用
以上两个方法更新过View后就要进行调用。
format包括:
类型 | 含义 |
---|---|
boolean | 布尔值 |
integer | 整数值 |
float | 浮点值 |
fraction | 百分数 |
string | 字符串 |
color | 颜色 |
dimension | 尺寸值 |
enum | 枚举 |
flag | 位或运算 |
reference | 资源引用 |
enum:
<attr name="属性名"> <enum name="名称" value="值" /> <enum name="名称" value="值" /> </attr>
flag:
<attr name="属性名"> <flag name="名称" value="值" /> <flag name="名称" value="值" /> ... ... </attr>
format参考:http://blog.csdn.net/mayingcai1987/article/details/6216655
//////
以上内容可参考:http://blog.csdn.net/allen315410/article/details/39343401
//////
三 控件组合,模板化使用
这种自定义组件的方式并不创建新的组件,只是将已有组件进行组合,然后将组合好的整体当做模板来使用。关键方法:
1
LayoutInflater.from(Context).inflate(自定义布局id, 为加载好的布局指定父布局);
通过以上关键代码来将自定义布局载入程序中,之后就可以通过
findViewById来获取自定义布局文件中的组件了。
步骤如下:
1. 根据需求进行组件组合
根据需求对组件进行组合,构成模板。此处主要是实现一个XML布局文件。
2. 拓展Layout类
实现Layout类的子类,在其具有两个参数的构造方法中加载上一步实现的布局文件,然后获取其中定义的组件。
3. 控制组件显示,实现事件响应
根据需求,操作上一步获取的组件,控制组件显示并实现具体的事件响应。
示例程序:E:\code\ExampleBest\test_selfdefinewidget
四 继承View,重写onDraw()方法,进行重绘;继承ViewGroup,重写相关方法,实现布局
继承View与继承ViewGroup是不同的。继承View是要自定义组件,而继承ViewGroup则要自定义布局。对于自定义组件而言,所需要考虑比较少,只有两点需要注意:
1. 对于Touch事件的处理;
根据事件处理机制,当重写了
onTouch方法后,要注意返回true之后会导致
onTouchEvent方法不再执行,进而影响到click的执行与滑动的效果;同时,还要注意对ACTION的DOWN处理后返回false时,会导致后续的UP、MOVE事件无法获取,也就是会阻止事件的层级传递。
2. 重写
onDraw方法绘制需要的UI。
根据Android绘制原理,对于自定义View的绘制,只需要重写
onDraw方法即可,在其中使用所提供的Canvas画布绘制所需要的效果。
至于测量与布局,自定义组件不需要考虑太多,这是由布局组件来考虑的问题。事实上,View类中的
measure方法是一个final方法,子类无法重写,对于子类,只需要重写真正进行测量的
onMeasure方法即可,在View类中的
onMeasure实现里,只是去调用了
setMeasuredDimension这个final方法去保存了组件的宽、高信息。从直接继承自View的TextView源码情况来看,其重写了
onMeasure方法去根据padding等信息来计算宽、高数据。View类中的
layout方法则直接在注释中说明,子类不需要重写该方法,具有子组件的子类,需要重写
onLayout方法,在其中调用子组件的
layout方法,而View类中的
onLayout方法则是一个空方法。从TextView源码来看,其并没有重写
layout方法(因为不需要),所重写的
onLayout方法也没有进行重要的操作。所以,在自定义View组件时,为了实现较精细的测量,一般需要重写
onMeasure方法,对于
onLayout方法,一般不用实现。
对于自定义布局,就要考虑对于测量与布局的处理问题,
1. 测量
这一步根据Android绘制原理,需要重写
onMeasure方法,在其中获取各个子组件的dimension,计算出布局的dimension,然后调用
setMeasuredDimension方法设置好布局的尺寸。ViewGroup中没有重写
onMeasure方法,子类必须自己进行实现。
2. 布局
这一步需要重写
onLayout方法,在其中调用各个子组件的
layout方法,让子组件完成对自己的布局。在ViewGroup中,
onLayout方法是一个抽象方法,自定义的布局必须实现该方法,在其中对子组件的
layout方法进行调用。而ViewGroup中的
layout方法是一个final方法,不能被重写,其中则简单的调用了Super的
layout方法(
super.layout())。关于View的
layout方法,一般在进行继承View自定义组件时不需要重写,至于View类中的
onLayout方法,是一个空方法,不进行任何操作。
至于绘制,则由ViewRootImpl类中的
performTraversals方法调用
performDraw进而调用组件的
onDraw方法实现,不需要在ViewGroup中考虑。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories