Android視圖控制項架構分析之View、ViewGroup

来源:http://www.cnblogs.com/1992monkey/archive/2016/05/07/5466815.html
-Advertisement-
Play Games

在Android中,視圖控制項大致被分為兩類,即ViewGroup和View,ViewGroup控制項作為父控制項,包含並管理著子View,通過ViewGroup和View便形成了控制項樹,各個ViewGoup對象和View對象就是控制項樹中的節點。在控制項樹中,以樹的深度來遍歷查找對應的控制項元素,同時,上層控 ...


  在Android中,視圖控制項大致被分為兩類,即ViewGroup和View,ViewGroup控制項作為父控制項,包含並管理著子View,通過ViewGroup和View便形成了控制項樹,各個ViewGoup對象和View對象就是控制項樹中的節點。在控制項樹中,以樹的深度來遍歷查找對應的控制項元素,同時,上層控制項負責子控制項的測量與繪製,並傳遞交互事件。

  Android控制項樹:

  

  AndroidUI界面架構圖:

  

一.測量View的工具類:MeasureSpec

  1.MeasureSpec包含了測量的模式和測量的大小,通過MeasureSpec.getMode()獲取測量模式,通過MeasureSpec.getSize()獲取測量大小;

  2.MeasureSpec是一個32位的int值,高2位為測量的模式,低30位為測量的大小,使用位運算的目的在於提高優化效率。

二.測量的模式

  1.EXACTLY,精確值模式:將layout_width或layout_height屬性指定為具體數值或者match_parent。

  2.AT_MOST,最大值模式:將layout_width或layout_height指定為wrap_content。

  3.UNSPECIFIED: View想多大就多大

三.View類預設的onMeasure()方法只支持EXACTLY模式,如果要支持其它模式,就必須重寫onMeasure(),重寫onMeasure()的模板代碼:

 1 package com.example.demoapp.views;
 2 
 3 import android.content.Context;
 4 import android.view.View;
 5 
 6 public class MeasuredView extends View {
 7     public MeasuredView(Context context) {
 8         super(context);
 9     }
10     
11     @Override
12     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
13         // 調用父類的onMeasure()
14         super.onMeasure(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
15         // 或者直接調用父類的setMeasuredDimension(),因為父類的onMeasure()最終調用了setMeasuredDimension()
16         // setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
17     }
18     
19     /**
20      * 測量View的width
21      * @param measureSpec MeasureSpec對象
22      * @return View的width
23      */
24     private int measureWidth(int measureSpec) {
25         int result = 0;
26         int specMode = MeasureSpec.getMode(measureSpec);
27         int specSize = MeasureSpec.getSize(measureSpec);
28         
29         if (specMode == MeasureSpec.EXACTLY) {
30             result = specSize;
31         } else {
32             result = 200;
33             if (specMode == MeasureSpec.AT_MOST) {
34                 result = Math.min(result, specSize);
35             }
36         }
37         return result;
38     }
39     
40     /**
41      * 測量View的height
42      * @param measureSpec MeasureSpec對象
43      * @return View的height
44      */
45     private int measureHeight(int measureSpec) {
46         int result = 0;
47         int specMode = MeasureSpec.getMode(measureSpec);
48         int specSize = MeasureSpec.getSize(measureSpec);
49         
50         if (specMode == MeasureSpec.EXACTLY) {
51             result = specSize;
52         } else {
53             result = 200;
54             if (specMode == MeasureSpec.AT_MOST) {
55                 result = Math.min(result, specSize);
56             }
57         }
58         return result;
59     }
60 }

四.View的繪製

  1.2D繪圖必備利器——Canvas

  1)獲取Canvas對象的方式:

    a.由方法中的參數傳入,例如,View的onDraw()中有一個參數就是Canvas對象

    b.通過構造方法構造,即:Canvas canvas = new Canvas(bitmap),在Canvas的構造方法傳入一個Bitmap對象,即可獲取一個Canvas對象。通過傳入Bitmap對象構造Canvas對象的過程稱為“畫布的裝載”,傳入的Bitmap對象承載了多有繪製在Canvas上的像素信息,調用Canvas.drawXXX方法(如:Canvas.drawBitmap(bitmap, 0, 0, null))都將發生在該Bitmap對象上。

  2)利用Canvas繪圖

    a.通過Canvas.drwaXXX進行繪製操作將直接作用於Bitmap對象,當再次刷新View的時候,我們將會被繪製的Bitmap對象發生了改變;

    b.利用Canvas和Paint進行繪圖;

    c.不管多麼複雜、精美的空間,都可以被拆分為一個個小的圖形單元,我們只要找到這些圖形單元,就可以將控制項繪製出來。

五.ViewGroup的測量

  1.ViewGroup的作用:管理子View,如子View的大小、位置;

  2.ViewGroup通過遍歷子View,調用子View的Measure()來獲得每一個子View的測量結果;

  3.ViewGroup測量完子View,調用子View的Layout()將子View放到合適的位置;

  4.在自定義ViewGroup的時候,通常會重寫onLayout()控制子View的顯示;

  5.如果需要支持wrap_content屬性,必須重寫onMeasure()。

六、ViewGroup的繪製

  通常情況下,ViewGoup不需要繪製,但是ViewGroup會使用dispatchDraw()來繪製其子View。

七.自定義View

  1.自定義View的時候,通常需要重寫onDraw()來繪製View要顯示的內容,如果還需要支持wrap_content屬性,必須重寫onMeasure();

  2.通過自定義attrs屬性,可以設置新的View屬性;

  3.View中一些重要的回調方法:

    1)onFinishInflate():從XML中載入組建後回調;

    2)onSizeChanged():組件大小改變時回調;

    3)onMeasure():進行測量;

    4)onLayout():設置顯示的位置;

    5)onTouchEvent():觸摸事件。

  4.實現自定義View的三種常用方法:

    1)通過重寫onDraw()對原生控制項進行擴展;

    2)通過組合實現新的控制項,通常集成一個合適的額ViewGoup,再通過addView()給它添加指定功能的控制項,從而組合成新的複合控制項。

    3)重寫View實現全新的控制項,通過重寫onDraw(),onMeasure()實現繪製邏輯,重寫onTouchEvent()實現交互邏輯。

  5.自定義屬性

    1)自定義屬性的方法:在res資源目錄的values目錄下創建一個attrs.xml的屬性定義文件,文件模板:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <resources>
 3     <declare-styleable name="customAttr">
 4         <attr name="title" format="string" />
 5         <attr name="fontSize" format="dimension" />
 6         <attr name="fontColor" format="color" />
 7         <attr name="background" format="reference|color" />
 8         <attr name="fontStyle" format="enum" />
 9         <attr name="shadeSupport" format="boolean" />
10     </declare-styleable>
11 </resources>

    2)通過TypedArray獲取自定義屬性集,通過TypedArray.getString()、TypedArray.getColor()等方法獲取屬性值,模板代碼:

 1 package com.jy.myrecyclerview.test;
 2 
 3 import android.content.Context;
 4 import android.content.res.TypedArray;
 5 import android.util.AttributeSet;
 6 import android.view.View;
 7 
 8 import com.jy.myrecyclerview.R;
 9 
10 /**
11  * Created by 123 on 2016/5/6.
12  */
13 public class TestCustomAttrs extends View {
14     private Context mContext;
15     private AttributeSet mAttrs;
16     private String mTitle;
17     private float mFontSize;
18     private int mFontColor;
19     private int mBackground;
20     private int mFontStyle;
21     private boolean mShadeSupport;
22 
23     public TestCustomAttrs(Context context) {
24         super(context);
25         this.mContext = context;
26     }
27 
28     public TestCustomAttrs(Context context, AttributeSet attrs) {
29         super(context, attrs);
30         this.mContext = context;
31         this.mAttrs = attrs;
32     }
33 
34     public TestCustomAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
35         super(context, attrs, defStyleAttr);
36         this.mContext = context;
37         this.mAttrs = attrs;
38     }
39 
40     private void getCustomAttrs() {
41         TypedArray ta = mContext.obtainStyledAttributes(mAttrs, R.styleable.customAttr);
42         mTitle = ta.getString(R.styleable.customAttr_title);
43         mFontSize = ta.getDimension(R.styleable.customAttr_fontSize, 10);
44         mFontColor = ta.getColor(R.styleable.customAttr_fontColor, 0);
45         mBackground = ta.getColor(R.styleable.customAttr_background, 0);
46         mFontStyle = ta.getInt(R.styleable.customAttr_fontStyle, 0);
47         mShadeSupport = ta.getBoolean(R.styleable.customAttr_shadeSupport, false);
48         ta.recycle();
49     }
50 }

  6.定義回調介面,實現自定義控制項的靈活控制;

  7.引用UI模板

    1)自定義控制項需要使用命名空間進行引入:xmlns:custom="http://schemas.android.com/apk/res-auto",即將自定義控制項的命名空間取名為custom

    2)在XML文件中使用自定義屬性的時候,就可以通過這個命名空間來引用,代碼模板如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.jy.myrecyclerview.test.TestCustomAttrs
        android:id="@+id/id_recyclerview"
        android:divider="#ffff0000"
        android:dividerHeight="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        custom:title="title"
        custom:fontSize="12sp"
        custom:fontColor="@color/colorPrimary"
        custom:background="@color/colorPrimary"
        custom:shadeSupport="false" />

</RelativeLayout>

  九.自定義ViewGroup

  1.需要重寫的方法:

    1)onMeasure():對子View進行測量;

    2)onLayout():設置子View的位置;

    3)onTouchEvent():設置觸摸交互事件。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 摘要 在各種BS架構的應用程式中,往往都希望服務端能夠主動地向客戶端推送各種消息,以達到類似於郵件、消息、待辦事項等通知。 往BS架構本身存在的問題就是,伺服器一直採用的是一問一答的機制。這就意味著如果客戶端不主動地向伺服器發送消息,伺服器就無法得知如何給客戶端推送消息。 隨著HTML、瀏覽器等各項 ...
  • DIV+CSS 清除浮動是頁面佈局中常見的問題,相信各位高手也都有自己的方法,今天在這裡對常見的幾種方法進行總結(PS:談不上是原創,這裡是我自己做的歸納總結,也是我自己內化的過程),希望對您能夠有所幫助。感謝博客園平臺! 來自<一隻有夢想的前端小白> DIV+CSS 浮動效果是指,父元素在未定義高 ...
  • 在js中有幾種模式可以創建對象,通過對象操作所包含的屬性與方法。 一般來說,構造函數名稱的第一個字母為大寫字母,非構造函數名稱的第一個字母為小寫字母,當然,構造函數與一般函數唯一的區別隻是調用的方式不同而已,所以任何函數只要通過new來調用,那它就可以作為構造函數,若不通過new來調用,則與一般函數 ...
  • 效果: ...
  • 本例子實現彈窗的效果: 1、jquery.show.js "); title=$(" "); content=$(" "); showdiv.html(""); showdiv.append(close); showdiv.append(title); showdiv.append(content) ...
  • 全部學習資源下載:http://pan.baidu.com/s/1eSGy3Qi 效果預覽:http://wjf444128852.github.io/demo/baiduditu/index.html html5里完全支持百度地圖 使用步驟 1、 引入百度地圖的JS * 鏈接 - http://a ...
  • 這次我們來講解第三節知識,考慮了下,先不去講什麼理論了,畢竟網上一搜一大堆,而且理論真心看不太懂啊!!! 今天我們就直接上實例嘍! 大家HIGH起來!!!(想了好久,還是沒捨得刪這句話) 1.根據下圖配置自己的文件 2.我們先用原始方法 額,忘記告訴大家做什麼項目了,那就在這補上吧,咱們先做一個小D ...
  • 在一個類的實例記憶體被釋放之前,析構方法被立即調用。使用deinit關鍵字來聲明析構方法,類似於構造方法用init來聲明。析構方法只適用於類類型。 析構方法原理 Swift會自動釋放不再需要的實例以釋放資源。如自動引用計數那一章描述,Swift通過自動引用計數(ARC)處理實例的記憶體管理。不需要手動的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...