View和ViewGroup的基本绘制流程
2016-09-19 14:42
141 查看
需要了解的
先来张图说明一下它们的关系你还要知道ViewGroup之间是可以嵌套的.
View的绘制流程
不知道大家有没有这种疑惑, 为什么我们在写布局文件的时候, 一定要写layout_width和layout_height呢, 难道就没有默认值吗? 颜色, 背景, 等等其他的都有默认值, 为什么宽高就一定要我们手动写呢? 接下来就让我们一起来解答这个疑惑吧.绘制流程的源码就不贴出来了, 有兴趣的可以打开View的源码对照着来看, 印象会更深刻, 当然, 不看源码, 理解以下的实例代码, 也不会影响你对整个流程的理解.
首先看一下View的绘制流程示例:
public class MyView extends View { private static final String TAG = "MyView"; public MyView(Context context, AttributeSet attrs) { super(context, attrs); } /** * measure - > onMeasure ,view的源码中,measure会调用onMeasure */ @Override protected void onMeasure(int widthMeasureSpec, int< 4000 /span> heightMeasureSpec) { //测量, 表示这个view的大小, 在View的源码中, Measure是final修饰的, 我们只能重写onMeasure方法 // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.d(TAG, "measure"); } /** * layout - > setFrame 和 onLayout */ @Override public void layout(int l, int t, int r, int b) { //布局,决定了摆放在父容器中的哪个位置 // TODO Auto-generated method stub super.layout(l, t, r, b); Log.d(TAG, "layout"); } /** * draw - > onDraw */ @Override public void draw(Canvas canvas) { //绘制 // TODO Auto-generated method stub super.draw(canvas); Log.d(TAG, "draw"); } }
以上就是View绘制显示在屏幕上必定会调用的三个方法, 可能你还不太理解, 不过没关系, 先混个脸熟, 有个印象先, 下面我们一个个分析.
View的onMeasure
来看一段Demopublic class MyView extends View { private static final String TAG = "MyView"; public MyView(Context context, AttributeSet attrs) { super(context, attrs); } /** * measure -> onMeasure * * 1.父容器拿到孩子的申请的宽高layout_width, layout_height封装成宽高的期望widthMeasureSpec和heightMeasureSpec * 父容器Relativelayout(或者其他Linearlyout) * 调用MyView的 measure(int widthMeasureSpec, int heightMeasureSpec)传入对孩子宽高的期望 * measure -> onMeasure(widthMeasureSpec, heightMeasureSpec) * * @param widthMeasureSpec 父容器(RelativeLaoyut)对孩子MyView的宽度期望, 跟layout_width相关 * @param heightMeasureSpec 父容器(RelativeLaoyut)对孩子MyView的高度期望, 跟layout_height相关 * 这是我们为什么一定要指定layout_width和layout_height的原因. */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { /** * int widthMeasureSpec * 32位二进制 * 前两位 是测量模式 mode * public static final int UNSPECIFIED = 0 << MODE_SHIFT; 父容器对孩子没有任何的限制,孩子想多大多大 * public static final int EXACTLY = 1 << MODE_SHIFT; 父容器对孩子有确切的大小要求,大小就会后30位 * public static final int AT_MOST = 2 << MODE_SHIFT; 父容器对孩子的最大值有要求,大小就会后30位 * 后30位表示大小 */ int mode = MeasureSpec.getMode(widthMeasureSpec); int size = MeasureSpec.getSize(widthMeasureSpec); Log.d(TAG, "onMeasure mode " + (mode>>30) + " " + size); //super方法默认使用父容器对我的期望的宽高 super.onMeasure(widthMeasureSpec, heightMeasureSpec); //我们也可以不调用super直接调用setMeasuredDimension(50, 50)来指定宽高 } }
注释里的setMeasuredDimension(int measuredWidth, int measuredHeight)是一个重要的方法, 它是整个测量结束的标志, 只有这个方法调用了, 我们才能调用getMeasuredWidth()或者getMeasuredHeight()方法获得测量宽高(注意, 不是实际宽高, 实际宽高要在布局完成之后)。
自定义View如果要使用wrap_content属性的话,则需重写onMeasure方法。
View的layout
layout方法里面调用setFrame(),给View的上下左右四个位置mLeft, mTop,mRight, mBottom赋值,完成布局工作.onLayout()是一个空的方法,说明具体的布局不应该由view来决定
我们的view并不需要关心layout方法, 布局的事应该交由父容器去处理, 让它决定它的孩子应该摆放在哪个地方.
在布局完成后, 我们才能调用getWidth()和getHeight获得实际的宽高.
getWidth()和getMeasuredWidth()的区别: getMeasureWidth()方法在measure()过程结束后就可以获取到了,而getWidth()方法要在layout()过程结束后才能获取到。另外,getMeasureWidth()方法中的值是通过setMeasuredDimension()方法来进行设置的,而getWidth()方法中的值则是通过视图右边的坐标减去左边的坐标计算出来的。
View的draw
view的绘制分为6步:对视图的背景进行绘制
If necessary, save the canvas’ layers to prepare for fading (暂时忽略它)
对视图的内容进行绘制, 在onDraw(canvas)方法中完成
对当前视图的所有子视图进行绘制 ,调用dispatchDraw。
If necessary, draw the fading edges and restore layers (暂时忽略它)
绘制装饰品(如滚动条)任何一个视图都是有滚动条的,只是一般情况下我们都没有让它显示出来而已.
即我们关心四个步骤:
绘制背景
绘制内容
绘制孩子
绘制装饰
绘制需要两个类, 画布(Canvas)和画笔(Paint), 通过以下Demo通过onDraw方法利用画笔在画布上绘制我们的图案吧.
public class MyView extends View { private Paint mPaint; private Bitmap mBitmap; private Path mPath; private RectF mOval; public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); //设置去锯齿 mPaint.setAntiAlias(true); //配置画笔,画空心圆 mPaint.setStyle(Style.STROKE); //设置画笔宽度 mPaint.setStrokeWidth(3); //设置画笔颜色 mPaint.setColor(Color.BLUE); //画图片时需要设置图片 mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.haha); //设置扇形的大小 mOval = new RectF(5, 5, 195, 195); initPath(); } private void initPath() { mPath = new Path(); //确定三个点 int x1 = 100, y1 = 5; int x2 = 195, y2 = 195; int x3 = 5, y3 = 195; //移动到第一个点 mPath.moveTo(x1, y1); //链接第一个点和第二个点 mPath.lineTo(x2, y2); //链接第二个点和第三个点 mPath.lineTo(x3, y3); mPath.lineTo(x1, y1); } /** * 不要在onDraw方法里面创建新的对象,因为onDraw方法可能会频繁调用 */ @Override protected void onDraw(Canvas canvas) { // 6. 裁剪 // canvas.clipPath(mPath); // 1. 画直线 // int startX =5, startY = 100; // int stopX = 195, stopY = 100; // canvas.drawLine(startX, startY, stopX, stopY, mPaint); // 2. 画圆 // int cx = 100, cy = 100; // int radius = 80; // canvas.drawCircle(cx, cy, radius, mPaint); // 3. 画空心圆 // 4. 画图片 // canvas.drawBitmap(mBitmap, 0, 0, mPaint); // 5. 画三角形 // canvas.drawPath(mPath, mPaint); //7.画扇形 int startAngle = -90; //开始的角度 int sweepAngle = 45; //扫过的角度 boolean useCenter = false;//是否画出扇形的两边 canvas.drawArc(mOval, startAngle, sweepAngle, useCenter, mPaint); } }
View的重新绘制
invalidate(); //触发View的重新绘制 onDrawpostInvalidate(); //请求在主线程重新绘制控件 onDraw
ViewGroup的绘制流程
ViewGroup继承View,绘制流程跟View是一致ViewGroup的测量
相同点:measure -> onMeasure不同点:ViewGroup需要在onMeasure去测量孩子
自定义ViewGroup一定要重写onMeasure方法,如果不重写则子View获取不到宽和高。重写是在onMeasure方法中调用measureChildern()方法,遍历出所有子View并对其进行测量。
ViewGroup的布局
相同点:layout (父容器调用) -》 onLayout不同点:ViewGroup需要实现onLayout方法去布局孩子,调用孩子的layout方法,指定孩子上下左右的位置
requestLayout();//请求重新布局 onLayout
ViewGroup的绘制
相同点:draw -> onDraw不同点:ViewGroup一般不绘制自己,ViewGroup默认实现dispatchDraw去绘制孩子
相关文章推荐
- Android学习自定义View(二)——View和ViewGroup绘制流程以及invalidate()
- AndroidView绘制流程分析及自定义View、ViewGroup进阶
- Android学习自定义View(二)——View和ViewGroup绘制流程以及invalidate()
- Android自定义ViewGroup的基本流程及用法演示
- View、ViewGroup的测量、布局、绘制流程
- Android 自定义View、ViewGroup(二)之绘制流程
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程以及invalidate()等相关方法分析
- 深入解析view和viewgroup绘制过程
- Android学习札记15:对Android中View绘制流程的一些理解
- Android中View绘制流程
- Android View绘制流程
- ViewContactActivity的基本流程
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程以及invalidate()等相关方法分析
- Android中View绘制流程