開發自己定義控件的步驟:
1、了解View的工作原理
2、 編寫繼承自View的子類
3、 為自己定義View類添加屬性
4、 繪制控件
5、 響應使用者消息
6 、自己定義回調函數
一、View結構原理
Android系統的視圖結構的設計也採用了組合模式,即View作為全部圖形的基類,Viewgroup對View繼承擴充為視圖容器類。
View定義了畫圖的基本操作
基本操作由三個函數完畢:measure()、layout()、draw(),其内部又分别包括了onMeasure()、onLayout()、onDraw()三個子方法。詳細操作例如以下:
1、measure操作
measure操作主要用于計算視圖的大小。即視圖的寬度和長度。在view中定義為final類型,要求子類不能改動。
measure()函數中又會調用以下的函數:
(1)onMeasure()。視圖大小的将在這裡終于确定,也就是說measure僅僅是對onMeasure的一個包裝,子類能夠覆寫onMeasure()方法實作自己的計算視圖大小的方式,并通過setMeasuredDimension(width, height)儲存計算結果。
2、layout操作
layout操作用于設定視圖在螢幕中顯示的位置。
在view中定義為final類型,要求子類不能改動。
layout()函數中有兩個基本操作:
(1)setFrame(l,t,r,b),l,t,r,b即子視圖在父視圖中的詳細位置,該函數用于将這些參數儲存起來。
(2)onLayout(),在View中這個函數什麼都不會做,提供該函數主要是為viewGroup類型布局子視圖用的。
3、draw操作
draw操作利用前兩部得到的參數,将視圖顯示在螢幕上。到這裡也就完畢了整個的視圖繪制工作。
子類也不應該改動該方法,由于其内部定義了畫圖的基本操作:
(1)繪制背景;
(2)假設要視圖顯示漸變框,這裡會做一些準備工作;
(3)繪制視圖本身。即調用onDraw()函數。在view中onDraw()是個空函數,也就是說詳細的視圖都要覆寫該函數來實作自己的顯示(比方TextView在這裡實作了繪制文字的過程)。而對于ViewGroup則不須要實作該函數,由于作為容器是“沒有内容“的。其包括了多個子view,而子View已經實作了自己的繪制方法。是以僅僅須要告訴子view繪制自己就能夠了,也就是以下的dispatchDraw()方法;
(4)繪制子視圖,即dispatchDraw()函數。在view中這是個空函數,詳細的視圖不須要實作該方法,它是專門為容器類準備的,也就是容器類必須實作該方法;
(5)假設須要(應用程式調用了setVerticalFadingEdge或者setHorizontalFadingEdge)。開始繪制漸變框。
(6)繪制卷軸框;
從上面能夠看出自己定義View須要最少覆寫onMeasure()和onDraw()兩個方法。
二、View類的構造方法
建立自己定義控件的3種主要實作方式:
1)繼承已有的控件來實作自己定義控件: 主要是當要實作的控件和已有的控件在非常多方面比較類似, 通過對已有控件的擴充來滿足要求。
2)通過繼承一個布局檔案實作自己定義控件。一般來說做組合控件時能夠通過這個方式來實作。
注意此時不用onDraw方法。在構造廣告中通過inflater載入自己定義控件的布局檔案。再addView(view)。自己定義控件的圖形界面就載入進來了。
3)通過繼承view類來實作自己定義控件,使用GDI繪制出元件界面。一般無法通過上述兩種方式來實作時用該方式。
三、自己定義View添加屬性的兩種方法:
1)在View類中定義。通過構造函數中引入的AttributeSet 去查找XML布局的屬性名稱,然後找到它相應引用的資源ID去找值。
案例:實作一個帶文字的圖檔(圖檔、文字是onDraw方法重繪實作)
布局檔案:
> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.example.myimageview2.MyView android:id="@+id/myView1" android:layout_width="wrap_content" android:layout_height="wrap_content" Text="@string/hello_world" Src="@drawable/xh"/> </LinearLayout>
屬性Text, Src在自己定義View類的構造方法中讀取。
2)通過XML為View注冊屬性。
與Android提供的标準屬性寫法一樣。
案例: 實作一個帶文字說明的ImageView (ImageView+TextView組合,文字說明。可在布局檔案裡設定位置)
LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); break; case R.styleable.MyImageView_Text: resourceId = typedArray.getResourceId( R.styleable.MyImageView_Text, 0); tv.setText(resourceId > 0 ?
typedArray.getResources().getText( resourceId) : typedArray .getString(R.styleable.MyImageView_Text)); break; case R.styleable.MyImageView_Src: resourceId = typedArray.getResourceId( R.styleable.MyImageView_Src, 0); iv.setImageResource(resourceId > 0 ?resourceId:R.drawable.ic_launcher); break; } } addView(iv); addView(tv); typedArray.recycle(); } }
attrs.xml進行屬性聲明。 檔案放在values檔案夾下
MainActivity的布局檔案:先定義命名空間 xmlns:uview="http://schemas.android.com/apk/res/com.example.myimageview2" (com.example.myimageview2為你
在manifest中定義的包名)
然後夠像使用系統的屬性一樣使用:uview:Oriental="Vertical"
四、控件繪制 onDraw()
五、
六:自己定義View的方法
onFinishInflate() 回調方法。當應用從XML載入該元件并用它建構界面之後調用的方法
onMeasure() 檢測View元件及其子元件的大小
onLayout() 當該元件須要配置設定其子元件的位置、大小時
onSizeChange() 當該元件的大小被改變時
onDraw() 當元件将要繪制它的内容時
onKeyDown 當按下某個鍵盤時
onKeyUp 當松開某個鍵盤時
onTrackballEvent 當發生軌迹球事件時
onTouchEvent 當發生觸屏事件時
onWindowFocusChanged(boolean) 當該元件得到、失去焦點時
onAtrrachedToWindow() 當把該元件放入到某個窗體時
onDetachedFromWindow() 當把該元件從某個窗體上分離時觸發的方法
onWindowVisibilityChanged(int): 當包括該元件的窗體的可見性發生改變時觸發的方法