39、自定义控件(四)-- View源码分析
一、View源碼分析
ViewRoot對應于ViewRootImpl類,它是連接WindowManager和DecorView的紐帶,View的三大流程全是通過ViewRoot來完成的。
在ActivityThread中,當Activity對象被創建后,會將DectorView添加到Window中,同時會創建ViewRootImpl對象,并將
ViewRootImpl對象和decorView建立關聯,這個過程我們可以參看源碼:
root = new ViewRootImpl(view.getContext(),display); root.setView(view,wparams,panelparentView);View的繪制流程是從ViewRoot的performTeaversals方法開始的,它經過measure、layout、draw三個過程才能最終將一個View繪制出來。
其中measure用來測量View的寬和高,layout用來確定View在父容器中放置的位置,而draw負責將View繪制在屏幕上。
針對performTraversals的大致流程:
如圖所示,performTraversals會依次調用performMeasure、performLayout和performDraw三個方法,分別完成頂級View的measure、layout和draw三大流程。
PperformMeasure會調用measure方法,measure方法又會調用onMeasure,其中onMeasure又會調用所有子元素的measure方法完成測量。
同理,performLayout和performDraw也是如此。
DecorView是頂級View,它其實是一個FrameLayout,View層的事件都先經過DecorView,然后才傳遞給我們的View。
1.1、Measure的原理
measure過程中,如果是View,則通過measure方法即可完成測量過程,如果是ViewGroup,則需要完成自己的測量過程外,
還會遍歷去調用所有子元素的measure方法,各個子元素再遞歸去執行這個流程。
1、View的measure過程
? View的measure過程由其measure方法完成,measure方法是被final修飾的方法,不能重寫。在View的measure方法中會去調用View的onMeasure方法,
因此只需要看onMeasure方法的實現即可:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }setMeasureDimension方法會設置View的寬和高來代表測量的結束,因此我們只需要看getDefaultSize方法即可:
public static int getDefaultSize(int size, int measureSpec) {int result = size;int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);switch (specMode) {case MeasureSpec.UNSPECIFIED:result = size;break;case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY:result = specSize;break;}return result; }對于我們來說只需要看AT_MOST和EXACTLY兩種情況,其實getDefaultSize返回的大小就是measureSpec中的specSize,它就是View測量后的大小。
而UNSPECIFIED這種情況一般用于系統內部的測量過程,在這種情況下,View的大小為getDefault的第一個參數size,即寬和高分別是
getSuggestedMinimumWidth和getSuggestedMinimumHeught這兩個方法的返回值。
protected int getSuggestedMinimumHeight() {return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); } protected int getSuggestedMinimumWidth() {return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); }可以看出,如果在沒有指定背景的情況下,寬度和高度分別是mMinWidth和mMinHeight,如果不指定該屬性,則默認為0.
如果指定背景的情況下,寬度和高度分別是max(mMinHeight, mBackground.getMinimumHeight())和max(mMinWidth, mBackground.getMinimumWidth())
那么我來看看mBackground.getMinimumWidth()方法:
public int getMinimumWidth() {final int intrinsicWidth = getIntrinsicWidth();return intrinsicWidth > 0 ? intrinsicWidth : 0; }可以看出,在Drawable有原始寬度的情況下,該方法返回的就是Drawable的原始寬度,當然高度也是如此。
轉載于:https://www.cnblogs.com/pengjingya/p/5510714.html
總結
以上是生活随笔為你收集整理的39、自定义控件(四)-- View源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 液晶电视品牌排行!(液晶电视品牌排行榜)
 - 下一篇: 品牌空调蚊帐使用技巧