成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android制霸控件View總結

移動開發
Android中控件大致被分為兩類ViewGroup,View。ViewGroup作為容器管理View。Android視圖,是類似于Dom樹的架構。父視圖負責測量定位繪制等操作。我們經常在用的findViewById方法代價昂貴的原因,就是因為他負責至上而下遍歷整棵控件樹,來尋找View實例,在重復操作中盡量少用。現在在用的很多控件都是直接或者間接繼承自View的

[[163808]]

關于Android View控件

Android中控件大致被分為兩類ViewGroup,View。ViewGroup作為容器管理View。Android視圖,是類似于Dom樹的架構。父視圖負責測量定位繪制等操作。我們經常在用的findViewById方法代價昂貴的原因,就是因為他負責至上而下遍歷整棵控件樹,來尋找View實例,在重復操作中盡量少用。現在在用的很多控件都是直接或者間接繼承自View的,如下圖。

view 繼承樹

Android UI界面架構

每個Activity包含一個PhoneWindow對象,PhoneWindow設置DecorView為應用窗口的根視圖。在里面就是熟悉的TitleView和ContentView,沒錯,平時使用的setContentView()就是設置的ContentView。

UI 架構

Android是如何繪制View的?

當一個Activity啟動時,會被要求繪制出它的布局。Android框架會處理這個請求,當然前提是Activity提供了合理的布局。繪制從根視圖開始,從上至下遍歷整棵視圖樹,每一個ViewGroup負責讓自己的子View被繪制,每一個View負責繪制自己,通過draw()方法,繪制過程分三步走。

  • Measure
  • Layout
  • Draw

整個繪制流程是在ViewRoot中的performTraversals()方法展開的。部分源代碼如下。

  1. private void performTraversals() { 
  2.     ...... 
  3.     //最外層的根視圖的widthMeasureSpec和heightMeasureSpec由來 
  4.     //lp.width和lp.height在創建ViewGroup實例時等于MATCH_PARENT 
  5.     int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); 
  6.     int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); 
  7.     ...... 
  8.     mView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 
  9.     ...... 
  10.     mView.layout(00, mView.getMeasuredWidth(), mView.getMeasuredHeight()); 
  11.     ...... 
  12.     mView.draw(canvas); 
  13.     ...... 

在繪制之前當然要知道view的尺寸和繪制。所以先進行measu和layout(測量和定位),如下圖。

繪制流程

Measure過程

  1. public final void measure(int widthMeasureSpec, int heightMeasureSpec) {   
  2.     //....   
  3.  
  4.     //回調onMeasure()方法     
  5.     onMeasure(widthMeasureSpec, heightMeasureSpec);   
  6.  
  7.     //more   

計算view的實際大小,獲得高寬存入mMeasuredHeight和mMeasureWidth,measure(int, int)傳入的兩個參數。MeasureSpec是一個32位int值,高2位為測量的模式,低30位為測量的大小。測量的模式可以分為以下三種。

  • EXACTLY
    精確值模式,當layout_width或layout_height指定為具體數值,或者為match_parent時,系統使用EXACTLY。

  • AT_MOST
    ***值模式,指定為wrap_content時,控件的尺寸不能超過父控件允許的***尺寸。

  • UNSPECIFIED
    不指定測量模式,View想多大就多大,一般不太使用。

根據上面的源碼可知,measure方法不可被重寫,自定義時需要重寫的是onMeasure方法。

  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
  2.         setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 
  3.                 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 
  4.     } 

查看源碼可知,最終的高寬是調用setMeasuredDimension()設定的,如果不重寫,默認是直接調用getDefaultSize獲取尺寸的。

使用View的getMeasuredWidth()和getMeasuredHeight()方法來獲取View測量的寬高,必須保證這兩個方法在onMeasure流程之后被調用才能返回有效值。

Layout過程

Layout方法就是用來確定view布局的位置,就好像你知道了一件東西的大小以后,總要知道位置才能畫上去。

  1. mView.layout(00, mView.getMeasuredWidth(), mView.getMeasuredHeight()); 

layout獲取四個參數,左,上,右,下坐標,相對于父視圖而言。這里可以看到,使用了剛剛測量的寬和高。

  1. public void layout(int l, int t, int r, int b) { 
  2.     int oldL = mLeft; 
  3.     int oldT = mTop; 
  4.     int oldB = mBottom; 
  5.     int oldR = mRight; 
  6.     boolean changed = setFrame(l, t, r, b); 
  7.     if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) { 
  8.         ..... 
  9.         onLayout(changed, l, t, r, b); 
  10.         ..... 

通過setFrame設置坐標。如果坐標改變過了,則重新進行定位。如果是View對象,那么onLayout是個空方法。因為定位是由ViewGroup確定的。

當layout結束以后getWidth()與getHeight()才會返回正確的值。

這里出現一個問題,getWidth/Height() 和 getMeasuredWidth/Height()有什么區別?

  • getWidth():View在設定好布局后View的寬度。
  • getMeasuredWidth():對View上的內容進行測量后得到的View內容占據的寬度。

getwidth

Draw過程

  1. public void draw(Canvas canvas) { 
  2.         ...... 
  3.         /* 
  4.          * Draw traversal performs several drawing steps which must be executed 
  5.          * in the appropriate order: 
  6.          * 
  7.          *      1. Draw the background 
  8.          *      2. If necessary, save the canvas' layers to prepare for fading 
  9.          *      3. Draw view's content 
  10.          *      4. Draw children 
  11.          *      5. If necessary, draw the fading edges and restore layers 
  12.          *      6. Draw decorations (scrollbars for instance) 
  13.          */ 
  14.  
  15.         // Step 1, draw the background, if needed 
  16.         ...... 
  17.         if (!dirtyOpaque) { 
  18.             drawBackground(canvas); 
  19.         } 
  20.  
  21.         // skip step 2 & 5 if possible (common case) 
  22.         ...... 
  23.  
  24.         // Step 2, save the canvas' layers 
  25.         ...... 
  26.             if (drawTop) { 
  27.                 canvas.saveLayer(left, top, right, top + length, null, flags); 
  28.             } 
  29.         ...... 
  30.  
  31.         // Step 3, draw the content 
  32.         if (!dirtyOpaque) onDraw(canvas); 
  33.  
  34.         // Step 4, draw the children 
  35.         dispatchDraw(canvas); 
  36.  
  37.         // Step 5, draw the fade effect and restore layers 
  38.         ...... 
  39.         if (drawTop) { 
  40.             matrix.setScale(1, fadeHeight * topFadeStrength); 
  41.             matrix.postTranslate(left, top); 
  42.             fade.setLocalMatrix(matrix); 
  43.             p.setShader(fade); 
  44.             canvas.drawRect(left, top, right, top + length, p); 
  45.         } 
  46.         ...... 
  47.  
  48.         // Step 6, draw decorations (scrollbars) 
  49.         onDrawScrollBars(canvas); 
  50.         ...... 
  51.     } 

重點是第三步調用onDraw方法。其它幾步都是繪制一些邊邊角角的東西比如背景、scrollBar之類的。其中dispatchDraw,是用來遞歸調用子View,如果沒有則不需要。

onDraw方法是需要自己實現的,因為每個控件繪制的內容不同。主要用canvas對象進行繪制,這里就不說了。

參考資料

  1. Android視圖繪制流程完全解析,帶你一步步深入了解View(二)
  2. Android應用層View繪制流程與源碼分析
  3. How Android Draws Views
  4. 《Android群英傳》
  5. What is the difference between getWidth/Height() and getMeasuredWidth/Height() in Android SDK?
責任編輯:倪明 來源: 簡書
相關推薦

2016-12-12 09:58:47

AndroidAndroid Vie

2019-09-18 15:23:32

AI 數據人工智能

2018-08-14 10:54:46

電競耳機

2013-08-08 10:03:03

云計算大數據NoSQL

2023-12-08 14:16:00

AI數據

2017-03-14 15:09:18

AndroidView圓形進度條

2009-12-30 13:30:16

Silverlight

2009-12-24 13:46:03

WPF控件

2009-12-30 13:51:43

Silverlight

2009-12-28 09:13:50

WPF容器控件

2009-08-17 09:24:25

ASP.NET控件

2017-12-07 08:51:34

2009-12-23 18:16:35

WPF布局控件

2014-03-28 13:14:33

2021-09-26 08:35:17

Android控件寬高

2017-02-17 09:37:12

Android自定義控件方法總結

2016-12-26 15:25:59

Android自定義View

2021-08-26 07:38:41

AndroidMediaPlayerTextureView

2021-08-25 07:43:17

AndroidSurfaceViewTextureView
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人综合伊人 | 亚洲综合二区 | 久久久久免费精品国产小说色大师 | 91久久国产| 国产乱码精品1区2区3区 | 国产成人精品一区二三区在线观看 | 91精产国品一二三区 | 欧美日韩成人一区二区 | 欧美成人视屏 | 蜜臀av日日欢夜夜爽一区 | 久久99精品国产自在现线小黄鸭 | av毛片免费| 精品一区二区三区免费毛片 | 欧美激情精品久久久久 | 久久久久久国产精品 | 精品国产乱码久久久久久a丨 | 久久综合国产 | 久久国产视频网站 | 久久久国产一区二区三区四区小说 | 亚洲h在线观看 | 亚洲资源在线 | 精品欧美一区二区精品久久久 | 99久久亚洲 | 三级av免费 | 国产永久免费 | 欧美午夜精品久久久久免费视 | 伊人在线 | 夜夜爽99久久国产综合精品女不卡 | 91天堂 | 日韩精品一区二区三区四区视频 | 亚洲国产精品一区二区久久 | 国产高清亚洲 | 久久亚洲国产精品日日av夜夜 | 青春草91 | av中文字幕在线播放 | 国产一区二区精 | 日韩av在线免费 | 精品国产欧美一区二区三区不卡 | 亚洲专区在线 | 国产成人精品视频 | 紧缚调教一区二区三区视频 |