天天看點

Android Viewgroup和View承擔角色的差別

一般來說,開發Android應用程式的UI界面都不會直接實用View和ViewGroup,而是使用這兩大基類的派生類。

 View 派生出的直接子類有:AnalogClock,ImageView,KeyboardView, ProgressBar,SurfaceView,TextView,ViewGroup,ViewStub 

   View 派生出的間接子類有:AbsListView,AbsSeekBar, AbsSpinner, AbsoluteLayout, AdapterView<T extends Adapter>,AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, AutoCompleteTextView,Button,CalendarView, CheckBox, CheckedTextView, Chronometer, CompoundButton, 

    ViewGroup派生出的直接子類有:AbsoluteLayout,AdapterView<T extends Adapter>,FragmentBreadCrumbs,FrameLayout,LinearLayout,RelativeLayout,SlidingDrawer 

    ViewGroup派生出的間接子類有:AbsListView,AbsSpinner, AdapterViewAnimator, AdapterViewFlipper, AppWidgetHostView, CalendarView, DatePicker, DialerFilter, ExpandableListView, Gallery, GestureOverlayView,GridView,HorizontalScrollView, ImageSwitcher,ListView,

  上述的所有基類、派生類都是Android framework層內建的标準系統類,開發者在應用開發中可直接引用SDK中這些系統類及其API。但事實上,在UI開發的很多場景下,直接使用這些系統類并不能滿足應用開發的需要。比如說,我們想用ImageView在預設情況下加載一幅圖檔,但是希望在點選該View時View變換出各種圖像處理效果,這個時候直接使用ImageView是不行的,此時我們可以重載ImageView,在新派生出的子控件中重載OnDraw等方法來實作我們的定制效果。這種派生出系統類的子類方法我們通常稱之為自定義控件。

  protected void onDraw(Canvas canvas):View類中用于重繪的方法,這個方法是所有View、ViewGroup及其派生類都具有的方法,也是Android UI繪制最重要的方法。開發者可重載該方法,并在重載的方法内部基于參數canvas繪制自己的各種圖形、圖像效果。

  protected void onLayout(boolean changed, int left, int top, int right, int bottom):View類中布局發生改變時會調用的方法,這個方法是所有View、ViewGroup及其派生類都具有的方法,重載該類可以在布局發生改變時作定制處理,這在實作一些特效時非常有用。

  protected void dispatchDraw(Canvas canvas):ViewGroup類及其派生類具有的方法,這個方法主要用于控制子View的繪制分發,重載該方法可改變子View的繪制,進而實作一些複雜的視效,典型的例子可參見Launcher子產品Workspace的dispatchDraw重載。

  protected boolean drawChild(Canvas canvas, View child, long drawingTime)):ViewGroup類及其派生類具有的方法,這個方法直接控制繪制某局具體的子view,重載該方法可控制具體某個具體子View。

 ViewGroup是View的子類,是以它也具有View的特性,但它主要用來充當View的容器,将其中的View視作自己的孩子,對它的子View進行管理,當然它的孩子也可以是ViewGroup類型。

    ViewGroup(樹根)和它的孩子們(View和ViewGroup)以樹形結構形成了一個層次結構,View類有接受和處理消息的功能,android系統所産生的消息會在這些ViewGroup和 View之間傳遞。

》繪制流程:

  繪制按照視圖樹的順序執行。視圖繪制時會先繪制子控件。如果視圖的背景可見,視圖會在調用onDraw函數之前繪制背景。強制重繪,可以使用invalidate()。

事件的基本流程如下:

  1、事件配置設定給相應視圖,視圖處理它,并通知相關監聽器。

  2、操作過程中如果發生視圖的尺寸變化,則該視圖用調用requestLayout()方法,向父控件請求再次布局。

  3、操作過程中如果發生視圖的外觀變化,則該視圖用調用invalidate()方法,請求重繪。

  4、如果requestLayout()或invalidate()有一個被調用,架構會對視圖樹進行相關的測量、布局和繪制。

  注意,視圖樹是單線程操作,直接調用其它視圖的方法必須要在UI線程裡。跨線程的操作必須使用句柄Handler。

》Android實作的是C/S模式:Activity的建立

【1】ActivityManagerService建立Activity線程,激活一個activity

【2】系統調用Instrumentation.newActivity建立一個activity

【3】Activity建立後,attach到一個新建立的phonewindow中。這樣Activity擷取一個唯一的WindowManager服務的執行個體

【4】Activity建立過程中使用setcontentView設定用使用者UI,這些VIEW被加入到PhoneWindow的ContentParent中。

【5】Activity線程繼續執行,當執行到Activity.makeVisible是将根view DecoView加入到WindowManger中,WindowManger實全會為每個DecoView建立對應的ViewRoot

【6】每個ViewRoot擁有一個Surface,每個Surface将會調用底層庫建立圖形繪制的記憶體空間。這個底層庫就是SurfaceFlinger。SurfaceFlinger同時也負責将個View繪制的圖形合到一塊(按照Z軸)顯示到使用者螢幕。

【7】如果使用者直接在Canvas上繪制,實際上它直接操作Surface。但對每個View的變更,它是要通知到ViewRoot,然後 ViewRoot擷取Canvas。如果繪制完成,surfaceFlinger得到通知,合并Surface成一個Surface到裝置螢幕。

     真正顯示圖形的實際上跟Activity沒有關系,完全由WindowManager來決定。 WindowManager是一個系統服務,是以可以直接調用這個服務來建立界面,并且更絕的是Dialog、Menu也是有WindowManager 來管理的。另外一個我們也可以看到,最底層都是Surface來,是以,常見開發遊戲的人都推薦你使用SurfaceView來建立界面。