剖析View和ViewGroup的渲染机制

近来一段时间,忙于对app架构的理解,脑袋里的浆糊也慢慢泡开了,终于有时间着手了解一个android最重要的2View的渲染过程(ViewViewGroup

分析:

第一部分(测量,measure

1. View的源码里面有3个方法

  public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 

.......

onMeasure(widthMeasureSpec, heightMeasureSpec);

........

  }

 

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

      setMeasuredDimension(

getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),

getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec)

);

     }

protected final void setMeasuredDimension(int measuredWidth, int  measuredHeight) {

 

根据上面3个方法可以看出三个方法的调用过程

------->Measure------->onMeasure

------->setMeasuredDimension

2.ViewGroup里面未重写 上面3个方法,而在ViewGroup的子类里面

FrameLayout. onMeasure里面有{

child.measure(childWidthMeasureSpec,  childHeightMeasureSpec);

}

LinearLayout,onMeasure里面有{

 measureChildBeforeLayout(

        child, i, widthMeasureSpec, 0, heightMeasureSpec,

      otalWeight == 0 ? mTotalLength : 0);

}

 

GridLayout. onMeasure里面有{

   measureChildrenWithMargins(widthSpecSansPadding,

heightSpecSansPadding, true);

}

 

RelativeLayout. onMeasure里面有{

measureChild(child, params, myWidth, myHeight);

}

ViewPager  onMeasure里面有{

child.measure(widthSpec, mChildHeightMeasureSpec);

}

不管以为什么方式 onMeasure里面都会调用到child.measure

 

所以看出来ViewGroup是呈递归测量的

Measure->(onMeasure->child.measure)(递归)

->setMeasuredDimension

3. 而在View里面的非ViewGroup子类中,

如:ImageViewTextView

虽然复写了onMeasure方法,但是最后还是会调用setMeasuredDimension

 

是不是有点晕? 没事有图

 

 

第二部分(布局,layouy

 

1. View的源码里面有这样2个方法

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

 

}

 public void layout(int l, int t, int r, int b){

onLayout(boolean changed, int left, int top, int right, int bottom) 

}

2. 可以看出 layout会调用 onLayout

 

3. ViewGroup中,onLayout变成了抽象方法,所以ViewGroup的子类都要去实现    它

protected abstract void onLayout(boolean changed,

int l, int t, int r, int b);

而最后跟进源码发现,ViewGroup的非抽象子类中都复写onLayout的时候都间接直接的调用了child.layout

 

FrameLayout. onLayout{

  child.layout(childLeft, childTop, childLeft + width, childTop +  height);

}

 

 

GridLayout. onLayout{

c.layout(cx, cy, cx + width, cy + height);

}

 

 

LinearLayout. onLayout{

protected void onLayout(boolean changed, int l, int t, int r, int b) {

         if (mOrientation == VERTICAL) {

            layoutVertical(l, t, r, b);

        } else {

            layoutHorizontal(l, t, r, b);

        }

}

}

 

RelativeLayout onLayout{

for(){

   child.layout(st.mLeft, st.mTop, st.mRight, st.mBottom);

}

}

所以看出来ViewGroup是逐级布局的

是不是有点晕? 没事有图

 

 

为什么这里不是递归的呢 稍等我们来认真的看一下View的源码

 

 public static boolean isLayoutModeOptical(Object o) {

        return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical();

    }

 

public void layout(int l, int t, int r, int b) {

        int oldL = mLeft;

        int oldT = mTop;

        int oldB = mBottom;

        int oldR = mRight;

//第一步,先判断是不是ViewGroup类型,

// ---不是的话(ViewGroupView子类)判断是否有变化并且设值

//  ---是的话(ViewGroup)也判断是否有变化并且设值

//第二步,观察该对象是否有变化,如果变化进入if

        boolean changed = isLayoutModeOptical(mParent) ?

                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);

        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {

//第三步调用onLayout(只有在viewGroup的子类中才会重写)

            onLayout(changed, l, t, r, b);

            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;

 

            ListenerInfo li = mListenerInfo;

            if (li != null && li.mOnLayoutChangeListeners != null) {

                ArrayList<OnLayoutChangeListener> listenersCopy =

                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();

                int numListeners = listenersCopy.size();

                for (int i = 0; i < numListeners; ++i) {

                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);

                }

            }

        }

        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;

    }

 

第三部分(渲染,ondraw

 

1. View的源码里面有这样2个方法

  protected void onDraw(Canvas canvas) {

    }

public void draw(Canvas canvas) {

onDraw(Canvas canvas) ;

}

2. 可以看出 draw会调用 onDraw

 

3. ViewGroup的子类中,并未复写这2个方法,而ViewGroup的有的子类复写

onDraw而有的没有 即使复写了也没draw子控件,但是ViewGroup 有个方法

protected boolean drawChild(Canvas canvas, View child, long drawingTime) {

         return child.draw(canvas, this, drawingTime);

}

    而drawChild 会在dispatchDraw 中被调用 让我们来看看dispatchDraw 方法 是啥玩意?

View的方法注释上有这么一段话

Called by draw to draw the child views. This may be overridden

by derived classes to gain control just before its children are drawn

(but after its own view has been drawn).

当这个方法调用的时候,就会渲染子控件,当时必须在控件渲染之后

 

当我寻遍了View的子类 发现毫无dispatchDraw 迹象,然后我在Viewdraw的方法里面发现调用了ViewdispatchDraw 真是不容易..........

其实onDraw执行判断玩后应该是dispatchDraw(Canvas canvas) 然后在ViewGroup里面实现了dispatchDraw(Canvas canvas),并且让方法里面去添加drawChildren

View的非ViewGroup里面dispatchDraw(Canvas canvas)是空实现。

那么我就重写画个图

 

 

 

后记:

虽然现在只能用用大神们的框架,很多人会觉得做这么多事情是多余的,当时我觉得但是分析控件的渲染过程还是有好处的,毕竟我们要去了解这些懂得的处理过程,然后去才能更好的去理解大神的框架,也许有一天,我们也能更好的维护出自己的小玩意,过段日子,准备看些源码,总结一下事件的传递机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值