編輯:關於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包括:
使用情況:
enum:
flag:
... ...
這種自定義組件的方式並不創建新的組件,只是將已有組件進行組合,然後將組合好的整體當做模板來使用。
關鍵方法:
1
LayoutInflater.from(Context).inflate(自定義布局id, 為加載好的布局指定父布局);
通過以上關鍵代碼來將自定義布局載入程序中,之後就可以通過findViewById
來獲取自定義布局文件中的組件了。
步驟如下:
1. 根據需求進行組件組合
根據需求對組件進行組合,構成模板。此處主要是實現一個XML布局文件。
2. 拓展Layout類
實現Layout類的子類,在其具有兩個參數的構造方法中加載上一步實現的布局文件,然後獲取其中定義的組件。
3. 控制組件顯示,實現事件響應
根據需求,操作上一步獲取的組件,控制組件顯示並實現具體的事件響應。
示例程序:E:\code\ExampleBest\test_selfdefinewidget
繼承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中考慮。
先看效果: 現在很多的應用效果都需要做的炫些,像UC,以及天天靜聽,效果很炫的,源碼已經對外開放了,有興趣的可以去研究下的 上源碼main.xml&l
幾年前,看到過有個牛人用HTML5繪制了浪漫的愛心表白動畫。發現原來程序員也是可以很浪……漫…..的(PS:剛過520,被妹子罵
本文主要介紹如何使用tcpdump和wireshark對Android應用程序進行抓包並分析,需要說明的是在抓包之前,你的Android設備必須root過了,另外你的電腦
本文實例講述了Android利用Intent實現數據傳遞的方法。分享給大家供大家參考,具體如下:在Android開發過程中,很多人都熟悉Intent,這是個用於在多個Vi