一 概述
在android应用开发过程中,固定的一些控件和属性可能满足不了开发的需求,所以在一些特殊情况下,我们需要自定义控件与属性。ViewGroup亦继承于View,下面看View的绘制过程:
二 自定义View
1. 实现步骤
- 继承View类或其子类
- 复写view中的一些函数
- 为自定义View类增加属性(两种方式)
- 绘制控件(导入布局)
- 响应用户事件
- 定义回调函数(根据自己需求来选择)
2.哪些方法需要被重写
onDraw()
view中onDraw()是个空函数,也就是说具体的视图都要覆写该函数来实现自己的绘制。对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容“的(但必须实现dispatchDraw()函数,告诉子view绘制自己)。onLayout()
主要是为viewGroup类型布局子视图用的,在View中这个函数为空函数。onMeasure()
用于计算视图大小(即长和宽)的方式,并通过setMeasuredDimension(width, height)保存计算结果。onTouchEvent
定义触屏事件来响应用户操作。
还有一些不常用的方法:
- onKeyDown 当按下某个键盘时
- onKeyUp 当松开某个键盘时
- onTrackballEvent 当发生轨迹球事件时
- onSizeChange() 当该组件的大小被改变时
- onFinishInflate() 回调方法,当应用从XML加载该组件并用它构建界面之后调用的方法
- onWindowFocusChanged(boolean) 当该组件得到、失去焦点时
- onAttachedToWindow() 当把该组件放入到某个窗口时
- onDetachedFromWindow() 当把该组件从某个窗口上分离时触发的方法
- onWindowVisibilityChanged(int): 当包含该组件的窗口的可见性发生改变时触发的方法
3. 自定义控件的三种方式
继承已有的控件
当要实现的控件和已有的控件在很多方面比较类似, 通过对已有控件的扩展来满足要求。继承一个布局文件
一般用于自定义组合控件,在构造函数中通过inflater和addView()方法加载自定义控件的布局文件形成图形界面(不需要onDraw方法)。继承view
通过onDraw方法来绘制出组件界面。
4. 自定义属性的两种方法
- 在布局文件中直接加入属性,在构造函数中去获得。
1 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
获取属性值:
1 | public myView(Context context, AttributeSet attrs) { |
- 在res/values/ 下建立一个attrs.xml 来声明自定义view的属性。
可以定义的属性有:
1 | <declare-styleable name = "名称"> |
attrs.xml进行属性声明
1 | <?xml version="1.0" encoding="utf-8"?> |
添加到布局文件
1 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
这里注意命名空间: xmlns:前缀=”http://schemas.android.com/apk/res/包名(或res-auto)”.
在构造函数中获取属性值:
1 | public myView(Context context, AttributeSet attrs) { |
或者:
1 | public myView(Context context, AttributeSet attrs) { |
5.代码示例
实现一个随手指移动的小球。具体步骤:
- 在res/values/ 下建立一个attrs.xml 来声明自定义view的属性
- 一个继承View并复写部分函数的自定义view的类
- 一个展示自定义view 的容器界面
a .自定义view命名为myView,它有一个属性值,格式为color
1 | <?xml version="1.0" encoding="utf-8"?> |
b. 在构造函数获取获得view的属性配置和复写onDraw和onTouchEvent函数实现绘制界面和用户事件响应
1 | public class myView extends View{ |
这里通过不断的更新当前位置坐标和重新绘制图形实现效果,要注意的是使用TypedArray后一定要记得recycle(). 否则会对下次调用产生影响。
c. 把myView加入到activity_main.xml布局里面
1 | <?xml version="1.0" encoding="utf-8"?> |
d. 最后是MainActivity
1 | public class MainActivity extends AppCompatActivity { |
注:具体的view要根据具体的需求来,比如我们要侧滑删除的listview我们可以继承listview,监听侧滑事件,显示删除按钮实现功能。
三 自定义ViewGroup
自定义ViewGroup比自定义View要麻烦一些,因为ViewGroup需要去计算子View的大小以此来改变ViewGroup的大小,同时我们还要知道子View的摆放顺序。
1.源码分析
等我看了再说
自定义ViewGroup的时候一般复写:
- onMeasure()方法:
计算childView的测量值以及模式,以及设置自己的宽和高 - onLayout()方法
对其所有childView的位置进行定位
2.代码示例
- onMeasure方法
1 |
|
- onLayout方法
1 | //存储所有的View |
- MainActivity.java
1 | public class MainActivity extends Activity { |