思维导图
知识点补充
坐标详解
View提供获取坐标方法
1 | View的坐标系:是相对于父控件而言的 |
getTop(): 获取View自身顶边到其父布局顶边的距离。
getLeft(): 获取View自身左边到其父布局左边的距离。
getRight(): 获取View自身右边到其父布局左边的距离。
getBottom(): 获取View自身底边到其父布局顶边的距离。
getTranslationX(): 计算的是该View在X轴的偏移量。初始值为0,向左偏移值为负,向右偏移值为正。
getTranslationY(): 计算的是该View在Y轴的偏移量。初始值为0,向上偏移为负,向下偏移为证。
MotionEvent提供的方法
getX():获取点击点距离所在组件坐标系的左边距离,即视图坐标。
getY():获取点击点距离所在组件坐标系的顶边距离,即视图坐标。
getRawX():获取点击点距离整个屏幕左边距离,即绝对坐标。
getRawY():获取点击点距离整个屏幕顶边距离,即绝对坐标。
getMeasureWidth() 和 getWidth()
一般情况下相等,获取时机不一样。
getMeasureWidth(): measure() 结束后可以获取,通过 setMeasuredDimension 设置的。
getWidth(): onLayout()之后才能获取,通过视图 右边的坐标 - 左边的坐标, 计算来的。
硬件加速
onMeasure, onLayout, onDraw 流程详解
onMeasure
Q: 最终测量的大小是如何确定的,有什么规则?
A: 大小是由设置的子元素的大小和所在父元素的测量规则一起决定。
Q: 在哪里实现遍历,测量子元素的宽高?自定义 view 的时候需要手动调用吗?
A: 需要手动调用。在父元素( ViewGroup ) 的 onMeasure 里面对子元素进行测量。根据控件需要,可以如下:
逐个测量的方法。比如 child.measure (包括内边距) 或者 child.measureChildWithMargins (包括内边距 + 外边距) 。
全部测量方法。 parent.measureChildren, 其内部实现也是去遍历 child.measure 。
onLayout
Q: 在哪里循环遍历,确定子元素的位置?自定义 view 的时候需要手动调用吗?
A: 需要手动调用。在父元素( ViewGroup )的 onLayout 里面,循环调用 child.layout 方法。以 RelativeLayout.java 为例:
1 |
|
onDraw
Q: 在哪里循环遍历,绘制子元素?自定义 view 的时候需要手动调用吗?
A: 不需要手动调用,View 在 onDraw 方法会调用 dispatchDraw ,而 ViewGroup 会实现该方法,在 dispatchDraw 进一步调用 drawChild 实现遍历绘制子元素。如下:ViewGroup.java
1 | @Override |
易忘点
1 | Path.Direction.CCW 逆时针 |
Q&A
自定义 view , xml预览空白
what: 控制台提示报错
1 |
|
when: 自定义view,在 xml 预览的时候。
why:自定义 view 里面,context 为 null,导致报错。
how:增加判断
if ( null == mContext ) return;
获取系统控件的某些xml定义值
Q: 在继承以后控件进行扩展的时候,有时候需要获取一些 xml的属性值,但是该值没有暴露接口,无法获取。或者获取的方法有版本兼容性问题,那么改怎么办呢?
A:举个例子:【实战1练习】我有个控件是继承 EditText, 实现右下角显示数字。这个时候我要获取 editText 的 maxLength。获取方法可以这样。
API > 21 的时候,系统有提供方法
1 | for (InputFilter filter : mEditText.getFilters()) { |
明显这些都不是好选择,那我们可以怎么做呢?
重新定义一个字段,在xml定义使用该字段代表 maxLength 的值,自定义 view 里面获取该字段。
定义 edit_text_count_max_length 字段
xml 声明的时候,使用该字段
自定义 view 时候使用该字段
实战练习
感谢
本文中思维导图里面引用的图片,来自下面参考文章里面的截图,感谢大佬们的总结。