系列学习:https://www.gcssloop.com/customview/CustomViewIndex/
一、View的生命周期
https://www.jianshu.com/p/08e6dab7886e
构造View() --> onFinishInflate() --> onAttachedToWindow() --> onMeasure() --> onSizeChanged() --> onLayout() --> onDraw() --> onDetackedFromWindow()
二、Canvas绘图
https://blog.csdn.net/CrazyMo_/article/details/48931681
1. 理解Canvas类
Canvas持有很多draw开头的方法,要想绘制一些东西,需要四个基本的元素:
1)一个保存像素的Bitmap
2)一个Canvas 调用drawxxx方法(画东西到bitmap)
3)要绘制的东西(矩形,路径,text,bitmap)
4)一个画笔
所以最终东西会被画到一个bitmap上,然后才渲染到屏幕上。
https://blog.csdn.net/u010126792/article/details/85158669
2. 构造方法
1)Canvas canvas = new Canvas();
// 构造一个空的canvas,然后利用setBitmap设置一个bitmap,为canvas指定画图的画布,最终的东西都被绘制在bitmap上
2)Canvas canvas = new Canvas(Bitmap bitmap); //类似空参构造,这里直接传入bitmap构造Canvas
3)通过重写View.onDraw方法,在这个方法里可以获得这个View对应的Canvas对象
3. 成员方法
1)绘制DrawXxxx系列(Xxxx代表Arc、Line、Text、RoundRect、Bitmap、Points等
2)得到画布中的各种对象getXxxx系列(Matrix、Height、width等)
3)保存和恢复画布(sace、restore)
4. Paint画笔
1)Paint paint = new Paint();
2)属性
setAntiAlias(boolean b); //抗锯齿
setDither(boolean b); // 防抖
5. 一些辅助类
1)矩形区域Rect和RectF
2)Matrix是一个3 x 3的矩阵,他对图片的处理分为四个基本类型:
平移变换Translate、缩放变换Scale、旋转变换Rotate、错切变换Skew
三、事件分发机制
1. View结构
2. 事件分发、拦截与消费
类型 | 相关方法 | Activity | VIewGroup | View |
---|---|---|---|---|
事件分发 | dispatchTouchEvent | ✔️ | ✔️ | ✔️ |
事件拦截 | onInterceptTouchEvent | ❌ | ✔️ | ❌ |
事件消费 | onTouchEvent | ✔️ | ✔️ | ✔️ |
-
Activity 作为原始的事件分发者,如果 Activity 拦截了事件会导致整个屏幕都无法响应事件,这肯定不是我们想要的效果。
-
View最为事件传递的最末端,要么消费掉事件,要么不处理进行回传,根本没必要进行事件拦截。
3. 事件分发流程
http://wuxiaolong.me/2015/12/19/MotionEvent/
https://www.yuque.com/mr.s/rznwxq/pmmegg#c0cbc06f
事件收集之后最先传递给 Activity, 然后依次向下传递,大致如下:
Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View
这样的事件分发机制逻辑非常清晰,可是,你是否注意到一个问题?如果最后分发到View,如果这个View也没有处理事件怎么办,就这样让事件浪费掉?
当然不会啦,如果没有任何View消费掉事件,那么这个事件会按照反方向回传,最终传回给Activity,如果最后 Activity 也没有处理,本次事件才会被抛弃:
Activity <- PhoneWindow <- DecorView <- ViewGroup <- ... <- View
4. 常见事件 MotionEvent
事件 | 简介 |
---|---|
ACTION_DOWN | 手指 初次接触到屏幕 时触发。 |
ACTION_MOVE | 手指 在屏幕上滑动 时触发,会会多次触发。 |
ACTION_UP | 手指 离开屏幕 时触发。 |
ACTION_CANCEL | 事件 被上层拦截 时触发。 |
- View的事件的调度顺序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener
- 不论 View 自身是否注册点击事件,只要 View 是可点击的就会消费事件
- 事件是否被消费由返回值决定,true 表示消费,false 表示不消费,与是否使用了事件无关
- ViewGroup 中可能有多个 ChildView 时,将事件分配给包含点击位置的 ChildView
- ViewGroup 和 ChildView 同时注册了事件监听器(onClick等),由 ChildView 消费
- 一次触摸流程中产生事件应被同一 View 消费,全部接收或者全部拒绝。
- 只要接受 ACTION_DOWN 就意味着接受所有的事件,拒绝 ACTION_DOWN 则不会收到后续内容
- 如果当前正在处理的事件被上层 View 拦截,会收到一个 ACTION_CANCEL,后续事件不会再传递过来