Android 知识点总结 (二) view绘制流程

相关文章:

Android 知识点总结(目录) https://blog.csdn.net/a136447572/article/details/81027701

view绘制主要包括三个方面:

measure 测量组件本身的大小
layout 确定组件在视图中的位置
draw 根据位置和大小,将组件画出来

measure
绘制组件的大小

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   }

重写onMeasure 是 会有两个参数 widthMeasureSpec与heightMeasureSpec 这连个参数是系统提供的控件高度的建议值但最终值需要通过setMeasuredDimension() 方法来设置

        int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);
        int widthMeasureMode = MeasureSpec.getMode(widthMeasureSpec);

        int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);
        int heightMeasureMode = MeasureSpec.getMode(heightMeasureSpec);

widthMeasureSpec与heightMeasureSpec 值 都是一个组合尺寸,它是一个32位bit值,高两位是尺寸模式specMode,低30位是尺寸大小值

可以通过 MeasureSpec.getSize() 与 MeasureSpec.getMode()方法分别获取尺寸模式和具体值

MeasureSpec.EXACTLY    用户指定 match_parent 或大小 :layout_width="50dip"
MeasureSpec.AT_MOST    用户指定 android:layout_width="wrap_content"
MeasureSpec.UNSPECIFIED  是用户未指定尺寸,这种情况不多

在 ViewGroup中 需要通过 measureChildren(widthMeasureSpec,heightMeasureSpec); 来计算ViewGroup中所有子View 的大小 然后通过 getChildCount()获取数量并循环计算总宽高

 measureChildren(widthMeasureSpec,heightMeasureSpec);
 int count = getChildCount();
 for (int i = 0; i < count ; i++) {
            View child = getChildAt(i);
            //计算过程 
            if ( (childWidth + lineWidth) > widthMeasure ){
                width = Math.max(lineWidth,childWidth);
                height += lineHeight;
                lineHeight = childHeight;
                lineWidth = childWidth;
            }else{
                lineWidth +=childWidth ;
                lineHeight = Math.max(lineHeight,childHeight);
            }
            if (i == count -1 ){
                height += lineHeight ;
                width = Math.max(width,lineWidth);
            }
}

最后得到计算出来的值 通过 setMeasuredDimension方法设置宽高值

  setMeasuredDimension((widthMeasureMode == MeasureSpec.EXACTLY)
                ?widthMeasure:width,(heightMeasureMode==MeasureSpec.EXACTLY)
                ?heightMeasure:height);

在计算中如果用户指定margin值时 则需要我们单独计算并添加,需要重写generateLayoutParams来获得准确的margin ,可以直接返回 new MarginLayoutParams(getContext(), attrs);

   @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }
 MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

onLayout

确定组件在视图中的位置 如果自定义时 是必须重写的方法

    @Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
    }

在onLayout 中 与onMeasure 相同,需要通过 int count = getChildCount(); 获取子View 数量 并通过循环设置每个view的layout

代码是其他自定义view的代码

@Override
    protected void onLayout(boolean b, int i, int i1, int i2, int i3) {

        int count = getChildCount();

        int lineWidth = 0;
        int lineHeight = 0;
        int top = 0;
        int left = 0;

        for (int j = 0; j < count; j++) {

            View child = getChildAt(j);

            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            if ((childWidth + lineWidth) > getMeasuredHeight()) {
                top += lineHeight;
                left = 0;
                lineHeight = childHeight;
                lineWidth = childWidth;
            } else {
                lineHeight = Math.max(lineHeight, childHeight);
                lineWidth += childWidth;
            }

            int lc = left + lp.leftMargin;
            int tc = top + lp.topMargin;
            int rc = lc + child.getMeasuredWidth();
            int bc = tc + child.getMeasuredHeight();

            child.layout(lc, tc, rc, bc);
            left += childHeight;

        }
    }

draw

根据位置和大小,将组件画出来

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
                mPath.reset();
        int originY = 300;
        int halfWaveLen = mItemWaveLength/2;
        mPath.moveTo(-mItemWaveLength+dx,originY+dy);
        for (int i = -mItemWaveLength;i<=getWidth()+mItemWaveLength;i+=mItemWaveLength){
            mPath.rQuadTo(halfWaveLen/2,-50,halfWaveLen,0);
            mPath.rQuadTo(halfWaveLen/2,50,halfWaveLen,0);
        }
        mPath.lineTo(getWidth(),getHeight());
        mPath.lineTo(0,getHeight());
        mPath.close();

        canvas.drawPath(mPath,mPaint);
        canvas.drawPath(path,mPaint1);
    }

onDraw 中 主要是通过在canvas上进行绘制连显示图片

view 在绘制的时候会通过上面这三个方法来确定view 的大小,位置,和其中的内容 ,最终显示到界面上

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值