美文网首页
自定义View相关问题

自定义View相关问题

作者: 王多鱼2 | 来源:发表于2019-08-21 15:59 被阅读0次

    1,自定义View的绘制流程?

    • 第一步:复写onMeasure方法。
      先measureChild方法 测量出所有子控件的moMeasure,
     //1,测量自身
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //2,为每个子view计算测量的限制信息
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
            //3,把上一步确定的限制信息,传递给每一个子view,然后子view开始measure自己的尺寸
            int childCount = getChildCount();//子view的个数
            for (int i = 0; i < childCount; i++) {
                View child = getChildAt(i);
                ViewGroup.LayoutParams lp = child.getLayoutParams();
                int childWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
                int childHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
                child.measure(childWidthSpec, childHeightSpec);
            }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         for (int i = 0; i < childCount; i++) {
                View child = getChildAt(i);
                //测量子view 获取到当前子view的测量的宽度和高度
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
        }  
    }
    

    调用 setMeasuredDimension(int measuredWidth, int measuredHeight)设置测绘后的大小。

     Log.i("tag","width = " + width );
            Log.i("tag","height = " + height );
            // 6,保存自身的尺寸
            setMeasuredDimension(width, height);
    
    • 第二步:onLayout方法
      在方法调用getChildCount方法 获取到子条目数量。
      用for循环遍历出每一个子条目的对象。 通过对象.layout方法 给子控件设置摆放位置。
      @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            //1,遍历子view的
            int left = 0;
            int top = 0;
            int right = 0;
            int bottom = 0;
    
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                View child = getChildAt(i);
                left = i * OFFSET;
                right = left + child.getMeasuredWidth();
                bottom = top + child.getMeasuredHeight();
                child.layout(left, top, right, bottom);//不考虑padding,margin等
                top += child.getMeasuredHeight();
            }
    
        }
    
    • 第三步:首先调用ViewGroup的disPatchDraw方法绘制ViewGroup。然后调用View中的onDraw方 进行绘制。

    2,自定义View是如何测量的 MeasureSpec

    方法内部需要调用MeasureSpec类 可以获取到view的模式 和 大小;
    MeasureSpec.getMode()获取模式
    MeasureSpec.getSize()获取大小​
    模式:

    • MeasureSpec.EXACTLY 精确值模式: 表示父控件已经确切的指定了子视图的大小。
    • MeasureSpec.AT_MOST 最大值模式:表示子查看具体大小没有尺寸限制,但是存在上限,上限一般为父视图大小。
    • MeasureSpec.UNSPECIFIED 父控件没有给子视图任何限制,子视图可以设置为任意大小
      什么时候这个模式会用到呢,看这边文章https://www.cnblogs.com/liushilin/p/11055741.html

    onDraw方法:
    用于绘制自定义View。
    主要使用到了Canvas 画布对象。 和Paint 画笔对象 进行的绘制。

    3,invalidate和postInvalidate方法的区别?requestLayout

    • requestLayout方法会导致View的onMeasure、onLayout、onDraw方法被调用;
    • invalidate方法则只会导致View的onDraw方法被调用;
    • invalidate方法和postInvalidate方法都是用于进行View的刷新,invalidate方法应用在UI线程中,而postInvalidate方法应用在非UI线程中,用于将线程切换到UI线程,postInvalidate方法最后调用的也是invalidate方法。
    • 我们在自定义View时,当需要刷新View时,如果是在UI线程中,那就直接调用invalidate方法,如果是在非UI线程中,那就通过postInvalidate方法来刷新View
    • postInvalidate方法实现了消息机制,最终调用的也是invalidate方法来刷新View
    • invalidate方法最终调用的是ViewRootImpl中的performTraversals来重新绘制View

    4 View的Touch事件分发流程?

    Touch事件的一般传递流程Activity->window(唯一实现类PhoneWindow)->顶级View(DecorView)->VIewGroup->View
    详情:预留

    4,图片圆角怎么实现

    5,LinearLayout、RelativeLayout源码;他们是怎么计算的,绘制方法流程;

    相关文章

      网友评论

          本文标题:自定义View相关问题

          本文链接:https://www.haomeiwen.com/subject/youbsctx.html