View的绘制流程-入门全套

1.Android-UI层级简介图

View的绘制流程-入门全套_第1张图片

其中PhoneWindow是最基本的窗口系统,是activity和view系统的交互接口。

每个activity都有一个PhoneWindow.

DecorView是所有view的祖先。

2.view绘制流程简介

Viewgroup也继承View.

每个view负责绘制自己,viewgroup还负责通知view绘制。

流程分为3步:测量(Measure),布局(Layout),绘制(Draw)

3.测量(Measure)

流程从根视图ViewRoot的performTraversals()方法开始:

View的绘制流程-入门全套_第2张图片

View的绘制流程-入门全套_第3张图片

View的绘制流程-入门全套_第4张图片

在上图标记出,还有一种情况经常要重写onMeasure(),就是判断specMode,区分at_most和exactly模式,分不同情况setMeasureDimension。

接下来是如果viewgroup.measure(),则有


4.布局(Layout)

会在例子中结合讲到,就是一个Layout()方法

5.绘制(Draw)

主要就是一个draw方法,例子中也会结合讲到。主要有6步:一般我们只需重写onDraw方法即可

View的绘制流程-入门全套_第5张图片

View的绘制流程-入门全套_第6张图片

6.流程讲到这里就完了,接下来写一个例子:

public class RectView extends View {
    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private int mcolor = Color.RED;

    public RectView(Context context) {
        super(context);
        initdraw();
    }

    public RectView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //如果有自定义的属性要用到,需加入下列代码:(自定义属性如何引用,下面会讲到)
        TypedArray typearray = context.obtainStyledAttributes(attrs , R.styleable.RectView);
        mcolor = typearray.getColor(R.styleable.RectView_rect_color , Color.RED);//没有设置该属性,默认为第2参数
        typearray.recycle();//获取资源必须及时回收

    initdraw();
    }

    public RectView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initdraw();
    }

    private void initdraw() {
        paint.setColor(mcolor);
        paint.setStrokeWidth(1.5f);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas); //默认的不计算padding
        /*//没有对padding做出改变,padding属性无效
        int width = getWidth();
        int height = getHeight();
        canvas.drawRect(0 , 0 , width , height , paint);*/

        //设置对layoutpadding的改变
        int paddingleft = getPaddingLeft();
        int paddingright = getPaddingRight();
        int paddingtop = getPaddingTop();
        int paddingbottom = getPaddingBottom();
        int width = getWidth() - paddingleft - paddingright;
        int height = getHeight() - paddingtop - paddingbottom;
        canvas.drawRect(paddingleft , paddingtop , paddingleft+width , paddingtop+height , paint);
    }

    //如果不对specMode分别处理,则wrap_content和match_parent的效果是一样的
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthspecmode = MeasureSpec.getMode(widthMeasureSpec);
        int widthspecsize = MeasureSpec.getSize(widthMeasureSpec);
        int heightspecmode = MeasureSpec.getMode(heightMeasureSpec);
        int heightspecsize = MeasureSpec.getSize(heightMeasureSpec);
        if (widthspecmode == MeasureSpec.AT_MOST && heightspecmode == MeasureSpec.AT_MOST){
            //如果宽度和高度都是用了wrap_content
            setMeasuredDimension(400 , 400);//默认的为setMeasureDimension(getDefaultSiza(getSuggestedMinimumWidth() , height一样写法)
        } else if (widthspecmode == MeasureSpec.AT_MOST){
            //只有宽度为wrap_content
            setMeasuredDimension(400 , heightspecsize);
        } else if (heightspecmode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthspecsize , 400);
        }

    }

}

如果要用到Layout()方法,可以在自定义view中再写一个onTouchEvent(),如下:

 public boolean onTouchEvent(MotionEvent event){
        int xx = (int) event.getX(); //在控件中的x
        int yy = (int) event.getY();

        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                lastx = xx;
                lasty = yy;
                break;

            case MotionEvent.ACTION_MOVE:
                setText("" + new Random().nextInt(10));
                int offsetx = xx - lastx; //得到偏移的距离
                int offsety = yy - lasty;

                /*//layout(),实现控件在viewgroup中的触摸滑动
                layout(getLeft()+offsetx ,
                        getTop() + offsety,
                        getRight() + offsetx,
                        getBottom() + offsety); //在移动过程中,不断重绘位置*/
                break;
        }
        return true;
    }
又比如想在控件中画些线条,可以在onDraw方法中添加代码:如:
protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int width = getWidth();
        int height = getHeight();
        canvas.drawLine(width/2 , 0 , width/2 , height , paint);
    }
}

7.解释上面的坐标计算:

坐标系分:A. android坐标系 和 B. view坐标系

A.android坐标系

View的绘制流程-入门全套_第7张图片

B.view坐标系

View的绘制流程-入门全套_第8张图片

各种计算结合如下图:

View的绘制流程-入门全套_第9张图片

getWidth() = getRight() - getLeft();

getHeight() = getBottom() - getTop();

8.入门就到这里了,做笔记,方便查看




你可能感兴趣的:(Android基础)