欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

揭秘Android视图绘制的流程步骤,

来源: 开发者 投稿于  被查看 31263 次 评论:77

揭秘Android视图绘制的流程步骤,


目录
  • 什么是View?
  • View的绘制过程
    • 测量阶段(Measure)
    • 布局阶段(Layout)
    • 绘制阶段(Draw)
  • View的绘制流程
    • Step 1:创建View
    • Step 2:测量View
    • Step 3:布局View
    • Step 4:绘制背景
    • Step 5:绘制内容
    • Step 6:绘制前景
    • Step 7:绘制子View
    • Step 8:完成绘制
  • 总结

    什么是View?

    View是Android系统中的一个基本组件,它是用户界面上的一个矩形区域,可以用来展示文本、图片、按钮等等。View可以响应用户的交互事件,比如点击、滑动等等。在Android中,所有的UI组件都是继承自View类。

    View的绘制过程

    View的绘制过程可以分为三个阶段:测量、布局和绘制。下面我们将逐一介绍这三个阶段。

    测量阶段(Measure)

    测量阶段是View绘制过程的第一个重要阶段。在测量阶段,系统会调用View的onMeasure方法,测量View的宽度和高度。在这个过程中,系统会根据View的LayoutParams和父容器的大小来计算出View的大小。

    例:下面代码是一个自定义View的onMeasure方法例程。在测量过程中,我们设定了View的大小。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 获取宽度的Size和Mode
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        // 如果Mode是精确的,直接返回
        if (widthMode == MeasureSpec.EXACTLY) {
            setMeasuredDimension(widthSize, heightMeasureSpec);
            return;
        }
        // 计算View的宽度
        int desiredWidth = getPaddingLeft() + getPaddingRight() + defaultWidth;
        int measuredWidth;
        if (desiredWidth < widthSize) {
            measuredWidth = desiredWidth;
        } else {
            measuredWidth = widthSize;
        }
        // 设置宽度和高度的Size和Mode
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int measuredHeight = defaultHeight;
        if (heightMode == MeasureSpec.EXACTLY) {
            measuredHeight = heightSize;
        } else if (heightMode == MeasureSpec.AT_MOST) {
            measuredHeight = Math.min(defaultHeight, heightSize);
        }
        setMeasuredDimension(measuredWidth, measuredHeight);
    }

    在测量阶段结束后,系统会将计算好的宽度和高度传递给布局阶段。

    布局阶段(Layout)

    布局阶段是View绘制过程的第二个重要阶段。在布局阶段,系统会调用View的onLayout方法,将View放置在父容器中的正确位置。在这个过程中,系统会根据View的LayoutParams和父容器的位置来确定View的位置。

    例:下面代码是一个自定义ViewGroup的onLayout方法例程。在布局过程中,我们遍历子View,并根据LayoutParams确定子View的位置和大小。

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();
        int left = getPaddingLeft();
        int top = getPaddingTop();
        int right = getMeasuredWidth() - getPaddingRight();
        int bottom = getMeasuredHeight() - getPaddingBottom();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE) {
                continue;
            }
            LayoutParams lp = (LayoutParams) child.getLayoutParams();
            int childLeft = left + lp.leftMargin;
            int childTop = top + lp.topMargin;
            int childRight = right - lp.rightMargin;
            int childBottom = bottom - lp.bottomMargin;
            child.layout(childLeft, childTop, childRight, childBottom);
        }
    }

    绘制阶段(Draw)

    绘制阶段是View绘制过程的最后一个重要阶段。在绘制阶段,系统会调用View的onDraw方法,绘制View的内容。在这个过程中,我们可以使用Canvas对象来绘制各种形状、文本和图片等等。

    例:下面代码是一个自定义View的onDraw方法例程。在绘制过程中,我们使用Paint对象绘制了一段文本。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制文本
        String text = "Hello World";
        Paint paint = new Paint();
        paint.setTextSize(50);
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);
        canvas.drawText(text, 0, getHeight() / 2, paint);
    }

    除了绘制内容,我们还可以在绘制阶段绘制View的背景和前景。系统会调用drawBackgrounddrawForeground方法来绘制背景和前景。值得注意的是,View的绘制顺序是:先绘制背景,再绘制内容,最后绘制前景。

    View的绘制流程

    View的绘制流程可以看作是一个递归调用的过程,下面我们将具体介绍这个过程。

    Step 1:创建View

    在View绘制过程的开始阶段,我们需要创建一个View对象,并将它添加到父容器中。在这个过程中,系统会调用View的构造函数,并将View的LayoutParams传递给它。

    Step 2:测量View

    接下来,系统会调用View的measure方法,测量View的宽度和高度。在这个过程中,View会根据自身的LayoutParams和父容器的大小来计算出自己的宽度和高度。

    Step 3:布局View

    在测量完成后,系统会调用View的layout方法,将View放置在父容器中的正确位置。在这个过程中,View会根据自身的LayoutParams和父容器的位置来确定自己的位置。

    Step 4:绘制背景

    在布局完成后,系统会调用View的drawBackground方法,绘制View的背景。在这个过程中,我们可以使用Canvas对象来绘制各种形状、文本和图片等等。

    Step 5:绘制内容

    接下来,系统会调用View的onDraw方法,绘制View的内容。在这个过程中,我们可以使用Canvas对象来绘制各种形状、文本和图片等等。

    Step 6:绘制前景

    在绘制内容完成后,系统会调用View的drawForeground方法,绘制View的前景。在这个过程中,我们同样可以使用Canvas对象来绘制各种形状、文本和图片等等。

    Step 7:绘制子View

    接着,系统会递归调用ViewGroup的dispatchDraw方法,绘制所有子View的内容。在这个过程中,我们可以使用Canvas对象来绘制各种形状、文本和图片等等。

    Step 8:完成绘制

    最后,所有的View绘制完成,整个View树也就绘制完成。

    例:下面代码是一个自定义ViewGroup的绘制流程例程。在绘制过程中,我们先画背景,再绘制每个子View的内容。

    public class MyViewGroup extends ViewGroup {
        public MyViewGroup(Context context) {
            super(context);
        }
        public MyViewGroup(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // 测量子View的宽高
            measureChildren(widthMeasureSpec, heightMeasureSpec);
            // 获取ViewGroup的宽高大小
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            // 设置ViewGroup的宽高
            setMeasuredDimension(widthSize, heightSize);
        }
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            // 遍历所有子View,设置它们的位置和大小
            int childCount = getChildCount();
            int left, top, right, bottom;
            for (int i = 0; i < childCount; i++) {
                View childView = getChildAt(i);
                left = childView.getLeft();
                top = childView.getTop();
                right = childView.getRight();
                bottom = childView.getBottom();
                childView.layout(left, top, right, bottom);
            }
        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 画背景
            canvas.drawColor(Color.WHITE);
        }
        @Override
        protected void dispatchDraw(Canvas canvas) {
            super.dispatchDraw(canvas);
            // 绘制每个子View的内容
            for (int i = 0; i < getChildCount(); i++) {
                View childView = getChildAt(i);
                childView.draw(canvas);
            }
        }
    }

    在ViewGroup的绘制流程中,系统会先调用ViewGroup的draw方法,然后依次调用dispatchDraw方法和绘制每个子View的draw方法。ViewGroup的绘制顺序是先绘制自己的背景,再绘制每个子View的内容和背景,最后绘制自己的前景。

    总结

    本文详细介绍了Android View的绘制过程,包括测量阶段、布局阶段和绘制阶段。同时,我们还在代码实现的角度,详细说明了Android ViewGroup的绘制流程,帮助你更好地理解和掌握Android的UI开发。

    以上就是揭秘Android视图绘制的流程步骤的详细内容,更多关于Android 视图绘制的资料请关注3672js教程其它相关文章!

    您可能感兴趣的文章:
    • Android Studio设置绘制布局时的视图
    • Android视图的绘制流程(上) View的测量
    • Android自定义控件(实现视图树绘制指示器)
    • Android基于OpenGL在GLSurfaceView上绘制三角形及使用投影和相机视图方法示例

    用户评论