天天看點

Android自己定義控件

開發自己定義控件的步驟:

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): 當包括該元件的窗體的可見性發生改變時觸發的方法