Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自定義組件使用總結

自定義組件使用總結

編輯:關於Android編程

一 概述

自定義組件有三種方式:
1. 繼承現有組件,拓展其功能;
2. 組合現有控件,實現模板化;
3. 繼承View,重寫onDraw()方法,進行重繪;繼承ViewGroup,重寫相關方法,實現布局。

二 繼承現有組件,拓展其功能

項目位置:E:\code\CustomViews\StudyTextView 以及 E:\code\CustomViews\StudyTextView0
運行效果:StudyTextView 通過點擊自定義組件RotateTextView,實現其文字內容的旋轉
StudyTextView0 實現自定義組件PaintDoubleWordsTextView,使其中的文字可隨手指移動
總結:
以上兩個自定義組件的實現原理均為繼承現有組件,並在現有組件的基礎上進行功能拓展。
具體而言,步驟如下:
1. 根據需要實現的功能選擇所要拓展的組件;
2. 自定義類繼承所要拓展的組件,這時,有以下幾個重要的方法需要重寫或使用:
重寫:
構造方法 – 如果要在XML文件中直接使用自定義組件,需要實現具有兩個參數的構造方法。這兩個參數分別為:Context 與 AttributeSet。
在構造方法中,主要實現獲取XML布局文件中寫入的自定義屬性的值。
在這之前,需要在res/values目錄下定義attrs.xml文件,該文件中定義了自定義組件支持的自定義屬性。具體寫法為:在resources標簽下加入declare-styleable標簽,並給其一個標簽名,一般選擇自定義類名作為標簽名;然後,在後面自定義屬性,以標簽attr包裹,內容包括自定義屬性名name與自定義屬性的類型format。形式如下所示:


    
        
        
        ... ...
    

這就定義了自定義控件的自定義屬性,之後就可以在XML布局文件中使用這些自定義屬性了。
使用的時候,要在xml文件中寫入xmlns,即xml命名空間,形式為:
xmlns:custom=”http://schemas.android.com/apk/res-auto”
或:
xmlns:custom=”http://schemas.android.com/apk/manifest中的package名”
之後就可以“custom:自定義屬性名”來使用自定義屬性了。
在構造方法中,通過操作TypedArray來獲取自定義屬性內容,代碼如下:

TypedArray options = context.obtainStyledAttributes(attrs, R.styleable.PaintDoubleWordsTextView, 0, 0);

int numOfOptions = options.getIndexCount();

for (int i = 0; i < numOfOptions; ++i) {
    int index = options.getIndex(i);
    switch (i) {
        case R.styleable.PaintDoubleWordsTextView_word0 :
            word0 = options.getString(index);
            break;
        case R.styleable.PaintDoubleWordsTextView_word0Size :
            word0Size = options.getInt(index, DEFAULT_TEXT_SIZE);
            break;
        case R.styleable.PaintDoubleWordsTextView_word1 :
            word1 = options.getString(index);
            break;
        case R.styleable.PaintDoubleWordsTextView_word1Size :
            word1Size = options.getInt(index, DEFAULT_TEXT_SIZE);
            break;
    }
}
options.recycle(); // 勿忘

onDraw() – 在該方法中繪制需要顯示的內容
onDraw()方法的參數是一個Canvas對象,通過該對象即可實現自定義組件的內容繪制。
使用:
invalidate() – 導致onDraw()被調用,刷新View
requestLayout() – 當前View的布局失效時就需要進行調用
以上兩個方法更新過View後就要進行調用。
format包括:

類型 含義 boolean 布爾值 integer 整數值 float 浮點值 fraction 百分數 string 字符串 color 顏色 dimension 尺寸值 enum 枚舉 flag 位或運算 reference 資源引用

使用情況:
enum:


    
    

flag:


    
    
    ... ...

 

三 控件組合,模板化使用

這種自定義組件的方式並不創建新的組件,只是將已有組件進行組合,然後將組合好的整體當做模板來使用。
關鍵方法:
1
LayoutInflater.from(Context).inflate(自定義布局id, 為加載好的布局指定父布局);
通過以上關鍵代碼來將自定義布局載入程序中,之後就可以通過findViewById來獲取自定義布局文件中的組件了。
步驟如下:
1. 根據需求進行組件組合
根據需求對組件進行組合,構成模板。此處主要是實現一個XML布局文件。
2. 拓展Layout類
實現Layout類的子類,在其具有兩個參數的構造方法中加載上一步實現的布局文件,然後獲取其中定義的組件。
3. 控制組件顯示,實現事件響應
根據需求,操作上一步獲取的組件,控制組件顯示並實現具體的事件響應。

示例程序:E:\code\ExampleBest\test_selfdefinewidget

四 繼承View,重寫onDraw()方法,進行重繪;繼承ViewGroup,重寫相關方法,實現布局

繼承View與繼承ViewGroup是不同的。繼承View是要自定義組件,而繼承ViewGroup則要自定義布局
對於自定義組件而言,所需要考慮比較少,只有兩點需要注意:
1. 對於Touch事件的處理;
根據事件處理機制,當重寫了onTouch方法後,要注意返回true之後會導致onTouchEvent方法不再執行,進而影響到click的執行與滑動的效果;同時,還要注意對ACTION的DOWN處理後返回false時,會導致後續的UP、MOVE事件無法獲取,也就是會阻止事件的層級傳遞。
2. 重寫onDraw方法繪制需要的UI。
根據Android繪制原理,對於自定義View的繪制,只需要重寫onDraw方法即可,在其中使用所提供的Canvas畫布繪制所需要的效果。
至於測量與布局,自定義組件不需要考慮太多,這是由布局組件來考慮的問題。事實上,View類中的measure方法是一個final方法,子類無法重寫,對於子類,只需要重寫真正進行測量的onMeasure方法即可,在View類中的onMeasure實現裡,只是去調用了setMeasuredDimension這個final方法去保存了組件的寬、高信息。從直接繼承自View的TextView源碼情況來看,其重寫了onMeasure方法去根據padding等信息來計算寬、高數據。View類中的layout方法則直接在注釋中說明,子類不需要重寫該方法,具有子組件的子類,需要重寫onLayout方法,在其中調用子組件的layout方法,而View類中的onLayout方法則是一個空方法。從TextView源碼來看,其並沒有重寫layout方法(因為不需要),所重寫的onLayout方法也沒有進行重要的操作。所以,在自定義View組件時,為了實現較精細的測量,一般需要重寫onMeasure方法,對於onLayout方法,一般不用實現
對於自定義布局,就要考慮對於測量與布局的處理問題
1. 測量
這一步根據Android繪制原理,需要重寫onMeasure方法,在其中獲取各個子組件的dimension,計算出布局的dimension,然後調用setMeasuredDimension方法設置好布局的尺寸。ViewGroup中沒有重寫onMeasure方法,子類必須自己進行實現。
2. 布局
這一步需要重寫onLayout方法,在其中調用各個子組件的layout方法,讓子組件完成對自己的布局。在ViewGroup中,onLayout方法是一個抽象方法,自定義的布局必須實現該方法,在其中對子組件的layout方法進行調用。而ViewGroup中的layout方法是一個final方法,不能被重寫,其中則簡單的調用了Super的layout方法(super.layout())。關於View的layout方法,一般在進行繼承View自定義組件時不需要重寫,至於View類中的onLayout方法,是一個空方法,不進行任何操作。
至於繪制,則由ViewRootImpl類中的performTraversals方法調用performDraw進而調用組件的onDraw方法實現,不需要在ViewGroup中考慮。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved