作为Android开发工程师一定会遇到一些特殊或者酷炫UI需求,当系统提供的View无法实现时,
我们可以通过自定义View来实现。自定义View大概可以分为组合View
、继承系统已有View组件
(例如TextView)和继承View或者ViewGroup
三大类。
先看下实现的效果:
想要实现自定义View需要了解哪些东西呢,请下面
生命周期
(1)Constructors()
View在代码中被创建时调用第一种构造方法,View从layout中加载出来时会被调用第二种构造方法,其中XML中的属性也会被解析。
(2)onFinishInflate()
该方法当View及其子View从XML文件中加载完成后触发调用。通常是在Activity中的setContent方法调用后调用。
(3)onVisibilityChanged()
该方法在当前View或其祖先的可见性改变时被调用。如果View状态不可见或者GONE,该方法会第一个被调用。
(4)onAttachedToWindow()
当View被附着到一个窗口时触发。在Activity第一次执行完onResume方法后被调用。
(5)onMeasure()
该方法确定View以及其子View尺寸大小时被调用。
(6)onSizeChanged()
该方法在Measure方法之后且测量大小与之前不一样的时候被调用。
(7)onLayout()
该方法在当前View需要为其子View分配尺寸和位置时会被调用。
(8)onDraw(Canvas)
该方法用于View渲染内容的细节。
(9)onWindowFocusChanged()
该方法也可能在绘制过程中被调用,具体是在包含当前View的Window获得或失去焦点时被调用。此时可以设置代码中定义的View的一些LayoutParameter。
如果View进入了销毁阶段,肯定是会被调用的。
(10)onWindowVisibilityChanged()
该方法同上,具体是在包含当前View的Window可见性改变时被调用。
(11)onDetachedFromWindow()
当View离开附着的窗口时触发,比如在Activity调用onDestroy方法时View就会离开窗口。和一开始的AttachedToWindow相对,都只会被调用一次。
坐标系
在Android坐标系中,以屏幕左上角作为原点,这个原点向右是X轴的正轴,向下是Y轴正轴。
View坐标系看下图:
- getTop():获取View到其父布局顶边的距离
- getLeft():获取View到其父布局左边的距离
- getBottom():获取View到其父布局顶边的距离
- getRight():获取View到其父布局左边的距离
- getX():表示的是触摸的点距离自身左边界的距离
- getY():表示的是触摸的点距离自身上边界的距离
- getRawX():表示的是触摸点距离屏幕左边界的距离
- getRawY():表示的是触摸点距离屏幕上边界的距离
自定义属性
在自定义View后编写values/attrs.xml,在其中编写styleable和item自定义属性标签元素
在布局文件中View使用自定义的属性(注意namespace),在View的构造方法中通过TypedArray获取
1 | <?xml version="1.0" encoding="utf-8"?> |
获取方式:
1 | public class MyTextView extends View { |
自定义view
- 重写构造方法
1 | public MyTextView(Context context) { |
- 重写onMeasure方法
我们可以通过onMeasure()方法提供的参数widthMeasureSpec和heightMeasureSpec来分别获取控件宽度和高度的测量模式和测量值(测量 = 测量模式 + 测量值)。
widthMeasureSpec和heightMeasureSpec虽然只是int类型的值,但它们是通过MeasureSpec类进行了编码处理的,其中封装了测量模式和测量值。
因此我们可以分别通过MeasureSpec.getMode(xMeasureSpec)和MeasureSpec. getSize(xMeasureSpec)来获取到控件或其子View的测量模式和测量值。
1 | 1) EXACTLY:当宽高值设置为具体值时使用,如100DIP、match_parent等,此时取出的size是精确的尺寸; |
-
重写onDraw方法
根据业务需求在onDraw方法中绘制UI,注意:不要将耗时操作或者初始化放到这个方法里
自定义ViewGroup时:
1).首先,我们得知道各个子View的大小,只有先知道子View的大小,我们才知道ViewGroup该设置为多大去容纳它们。
2).根据子View的大小,以及我们的ViewGroup要实现的功能,决定出ViewGroup的大小
3).ViewGroup和子View的大小算出来了之后,接下来就是去摆放了吧,具体怎么摆放?得根据你定制的需求去摆放,比如,你想让子View按照垂直顺序一个挨着一个放,或者是按照先后顺序一个叠一个去放,这是你自己决定的。
4).已经知道怎么摆放还不行啊,决定了怎么摆放就是相当于把已有的空间”分割”成大大小小的空间,每个空间对应一个子View,我们接下来就是把子View对号入座了,把它们放进它们该放的地方去。 -
重写OnLayout方法(摆放子View位置)
例如:
1 |
|
效果图源码
1 | public class TestView extends View { |