前言
在Android应用的开发里面,UI是非常重要的一部分。一般情况下,我们使用SDK自带的控件,加上一些开源库,已经可以实现大部分的UI效果了。但是要实现一些自定义效果得UI,往往需要通过自定义View来实现。掌握或是精通自定义View,无疑是加分技能。
绘制
- 方式:重写绘制方法(最常用的方法:onDraw(Canvas canvas))
绘制:Android里的绘制是在每个View的绘制方法里发生的,View的绘制方法里写了什么代码,它就会绘制成什么内容。而自定义View就是通过重写绘制方法,去绘制成想要实现的效果。
public class TextView extends View{
...
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
...//TextView的绘制代码
}
...
}
public class ImageView extends View{
...
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
...//ImageView 的绘制代码
}
...
}
public class MyView extends View{
...
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
...//MyView 的绘制代码
}
...
}
onDraw()这个绘制方法,它负责的是View的主体的绘制。例如TextView的文字、ImageView的图像,都是在onDraw()里绘制的。具体执行绘制操作的是onDraw()方法里的Canvas参数。
- 绘制关键:Canvas,Canvas是一个绘制工具,它唯一的功能就是绘制
- Canvas的绘制类方法:drawXX()
- Canvas的辅助类方法:范围裁切(clipXXX())和几何变换(Matrix)
- 使用不同的绘制方法来控制遮盖关系
测量、布局
布局过程的自定义
- 方式:重写布局过程的相关方法
- 测量过程:onMeasure()
- 布局过程:onLayout()
- 场景:
1、重写onMeasure()来修改已有的View的尺寸
方式:
1)、重写 onMeasure() 方法,并在里面调用 super.onMeasure() ,触发原有的自我测量;
2)、在 super.onMeasure() 的下面用getMeasuredWidth()和getMeasuredHeight()来获取到之前的测量结果,并使用自己的算法,根据测量结果计算出新的结果;
3)、调用setMeasuredDimension()来保存新的结果。
public class SquareTextView extends TextView {
...省略部分代码
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//先执行原测量算法
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取原先的测量结果
int measureWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
//利用原先的测量结果计算出新尺寸
if (measureWidth>measuredHeight){
measureWidth = measuredHeight;
}else {
measuredHeight = measureWidth;
}
//保存计算后的结果
setMeasuredDimension(measureWidth,measuredHeight);
}
}
2、重写onMeasure()来全新计算自定义View的尺寸
方式:
1)、重新onMeasure() ,并计算出View的尺寸;
UNSPECIFIED :不限制
AT_MOST :限制上限
EXACTLY :限制固定值
2)、使用 resolveSize() 来让子 View 的计算结果符合父View的限制
3、重写onMeasure()和onLayout()来全新计算自定义ViewGroup的内部布局
方式:
1)、重写 onMeasure() 来计算内部布局
调用每个子 View 的 measure() 来计算子 View 的尺寸;
计算子 View 的位置并保存子 View 的位置和尺寸;
计算自己的尺寸并用 setMeasuredDimension() 保存;
2)、重写 onLayout() 来摆放子View
在 onLayout() 里调用每个子 View 的 layout() ,让它们保存自己的位置和尺 寸。
触摸
- 重写onTouchEvent() ,在里面写上你的触摸反馈算法,并返回 true(关键是
ACTION_DOWN 事件时返回 true )。 - 如果是会发生触摸冲突的 ViewGroup ,还需要重写onInterceptTouchEvent() ,在事件流开始时返回 false ,并在确认接管事件流时返回一次true,以实现对事件的拦截。
- 当子 View 临时需要组织父 View 拦截事件流时,可以调用父View的requestDisallowInterceptTouchEvent() ,通知父View在当前事件流中不 再尝试通过 onInterceptTouchEvent() 来拦截。
总结
对View得实现原理有一个清晰得认识,在工作中,若是遇到相关bug,或需要实现自定义View,也知道从何下手。
网友评论