Android view的工作原理(Android开发艺术探索随笔)

  • ViewRoot
    ViewRoot对应的实现类是ViewRootImpl类,他是连接WindowManager和DecorView的纽带,view的三大 流程均是通过ViewRoot来完成的。在ActivityThread中,当activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联。

  • 三大流程

    measure performMeasure()->measure()->onMeasure()
    layout performLayout()->layout()->onLayout()
    draw performDraw()->draw()->onDraw()

  • MeasureSpec
    MeasureSpec代表一个32为int值,高2位代表SpecMode,低30位表示SpecSize。
    SpecMode有3类:
    1.UNSPENCIFIFD——父容器buduiview有限制,想要多大就多大,一般用于系统内部。
    2.EXACTLY——父容器已经检测出view所需要的精确大小,这个时候view的最终大小就是SpecSize指定的值。他对应于match_parent。
    3.AT_MOST——父容器指定一个大小,view大小不超过这个值。对应warp_content。


  • MeasureSpec和LayoutParams的对应关系
    对于普通的View,其measurespec由父容器的measurespec和自身的LayoutParams共同决定。
  • view采用固定宽高的时候,view的measurespec都是景区人模式并且大小遵循LayoutParams中的大小
  • 当view的宽高是match_parent的时候,如果父容器是精准模式,那么view也是精准模式并且大小是父容器的剩余空间。如果父容器是最大模式,view也是最大模式并且大小不会超过父容器剩余空间。
  • view是warp_content的时候, view的模式总是最大化并且不能超过父容器剩余空间。

measure过程

view的measure过程

view的measure有measure方法来完成。measure()方法中会调用onMeasure方法。代码如下

if (cacheIndex < 0 || sIgnoreMeasureCache) {
                // measure ourselves, this should set the measured dimension flag back
                onMeasure(widthMeasureSpec, heightMeasureSpec);
                mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }

onMeasure()方法代码如下,会调用getDefaultSize,返回的specSize就是测量后的大小

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
    }
protected int getSuggestedMinimumHeight() {
        return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight());

    }

如果view没有背景,view的高度就是mMinHeight,这个有android:minHeight控制。如果有背景,就是背景的最小高度。

ViewGroup的measure过程

viewgroup会测量子元素。

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
        final int size = mChildrenCount;
        final View[] children = mChildren;
        for (int i = 0; i < size; ++i) {
            final View child = children[i];
            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
            }
        }
    }
protected void measureChild(View child, int parentWidthMeasureSpec,
            int parentHeightMeasureSpec) {
        final LayoutParams lp = child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }

看到了layoutparams的身影。viewgroup是一个抽象类,跟着任教主,看看LinearLayout。

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mOrientation == VERTICAL) {
            measureVertical(widthMeasureSpec, heightMeasureSpec);
        } else {
            measureHorizontal(widthMeasureSpec, heightMeasureSpec);
        }
    }

measureVertical方法过于长,这个方法会测量子元素并记录目前的高度。


  • 在onCreate、onResume、onStart中去获取view的高度
    • onWindowFoucsChanged
    • view.post(Runnable)
    • ViewTreeObserver
    • view.measure() 这个比较复杂,具体的还的看书。

layout过程

确定4个顶点的位置,然后布局


draw过程

  • 绘制背景(background.draw)
  • 绘制自己(onDraw)
  • 绘制children(dispatchDraw)
  • 绘制装饰(onDrawScrollBars)

最后,关于自定义view,我觉得还是多去看看网上的一些大神给出的列子。这东西,看的多了,编的多了也就会了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值