Android自定義控件View的探討

本文轉載自:http://www.apkbus.com/forum.php?mod=viewthread&tid=242501&extra=page%3D1php



作過了一段時間的安卓開發都會接觸到自定義控件,那麼對於自定義控件你們都有什麼樣的見解呢?自定義控件他的優點是明顯的,設計他的思想又有哪些呢?會用到什麼模式呢?但願你們看了這個文章以後,能夠發表本身對於自定義控件的見解和思想,這個帖就是爲了跟你們交流而發。下面是我本身的一些見解,大俠們請指導!!!java


自定義View:android

在這裏咱們先來了解自定義控件view所須要的一些基礎知識,以及常見作法。web


自定義View類的構造方法數據庫

建立自定義控件的3種主要實現方式:設計模式


1)繼承已有的控件來實現自定義控件網絡

主要是當要實現的控件和已有的控件在不少方面比較相似, 經過對已有控件的擴展來知足要求。函數


2)經過繼承一個佈局文件實現自定義控件佈局

通常來講作組合控件時能夠經過這個方式來實現。單元測試

注意此時不用onDraw方法,在構造函數中經過inflater加載自定義控件的佈局文件,再addView(view),自定義控件的圖形界面就加載進來了。

例如:

假設我已經有了一個佈局的XML文件,裏面有一個textview和一個imageview,那麼在自定義view的構造方法裏這樣寫就可使用剛剛的佈局XML啦。


public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

inflater.inflate(R.layout.myView, this);

imageView=(ImageView) findViewById(R.id.imageView1);

textView=(TextView)findViewById(R.id.textView1);

}



3)經過繼承view類來實現自定義控件,使用GDI繪製出組件界面,通常沒法經過上述兩種方式來實現時用該方式。




自定義View增長屬性的兩種方法


1)在View類中定義。經過構造函數中引入的AttributeSet 去查找XML佈局的屬性名稱,而後找到它對應引用的資源ID去找值。


在下面自定義了兩個屬性Text, Src。

佈局文件:


<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical" >



<com.apkbus.MyView

android:id="@+id/myView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

Text="@string/hello_world"

Src="@drawable/logo"/>



</LinearLayout>


屬性Text, Src在自定義View類的構造方法中讀取。

Java代碼:


public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

int resourceId = 0;

int textId = attrs.getAttributeResourceValue(null, "Text",0);

int srcId = attrs.getAttributeResourceValue(null, "Src", 0);

mtext = context.getResources().getText(textId).toString();



}


2)經過XMLView註冊屬性。與Android提供的標準屬性寫法同樣。

例如:

須要自定義屬性Text,SelectSrc,先建立attrs.xml進行屬性聲明, 文件放在values目錄下。


<?xml version="1.0" encoding="utf-8"?>

<resources>



<declare-styleable name="MyView">

<attr name="Text" format="reference|string"></attr>

<attr name="Select" >

<enum name="open" value="1"></enum>

<enum name="close" value="0"></enum>

</attr>

<attr name="Src" format="reference|integer"></attr>

</declare-styleable>



</resources>


在佈局中使用這個自定義屬性:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:myView="http://schemas.android.com/apk/res/com.apkbus.myview"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

>



<com.apkbus.MyView

android:id="@+id/myView1"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

myView:Text="www.apkbug.com"

myView:Src="@drawable/img"

myView:Select="open">

</com.apkbus.MyView>



</LinearLayout>



說明:


在使用自定義佈局的時候須要添加這樣的一行在佈局的開頭位置

xmlns:myView="http://schemas.android.com/apk/res/com.apkbus.myview"


一、myView是自定義的一個命名空間,你能夠取一個喜歡的名稱。



二、"http://schemas.android.com/apk/res/com.apkbus.myview"這部分的字符串是由」http://schemas.android.com/apk/res/」和應用的包名」com.apkbus.myview」組成。




而後在自定義View類的構造方法中讀取


public MyView(Context context, AttributeSet attrs) {

super(context, attrs);

String pkName = "http://schemas.android.com/apk/res/" + context.getPackageName();

int textId = attrs.getAttributeResourceValue(pkName , "Text",0);

int srcId = attrs.getAttributeResourceValue(pkName , "Src", 0);

int select = attrs.getAttributeIntValue(pkName, "select", 0);

mtext = context.getResources().getText(textId).toString();



}



自定義View的經常使用方法

onFinishInflate() 回調方法,當應用從XML加載該組件並用它構建界面以後調用的方法


onMeasure() 檢測View組件及其子組件的大小


onLayout() 當該組件須要分配其子組件的位置、大小時


onSizeChange() 當該組件的大小被改變時


onDraw() 當組件將要繪制它的內容時


onKeyDown 當按下某個鍵盤時


onKeyUp  當鬆開某個鍵盤時


onTrackballEvent 當發生軌跡球事件時


onTouchEvent 當發生觸屏事件時


onWindowFocusChanged(boolean)  當該組件獲得、失去焦點時


onAtrrachedToWindow() 當把該組件放入到某個窗口時


onDetachedFromWindow() 當把該組件從某個窗口上分離時觸發的方法


onWindowVisibilityChanged(int): 當包含該組件的窗口的可見性發生改變時觸發的方法





View的設計理念:

看到這個小標題可能感受好高端,都到了理念的層次了。其實跟「View的設計目的」這個標題是差很少意思的。

作了開發這麼久了,我總結了大概這幾個設計的目的。


一、重用性目的

爲了能夠在不一樣的模塊、項目中重複使用而設計。



二、靈活性目的

自定義View能夠方便的實現系統提供的控件所沒有的功能,開發項目的時候靈活性大大增長。



三、解耦合目的

因爲自定義控件是相對獨立的,天然其與其餘模塊之間的耦合性也是比較低的。模塊間解耦天然就不可或缺咯。



既然有了目的,那麼怎麼實現就成爲如下命題了,在這裏我想跟大家談談設計模式。

在前面你們已經瞭解了實現一個自定義View的基本方法,可是作起來估計也是躡手躡腳的,不知道該如何具體的實現,我把這種迷惘叫缺乏指導思想。


這裏的指導思想就是設計模式,業務邏輯代碼應該放哪?UI代碼應該放哪?數據存儲代碼又應該放哪?只有明確了上面三個問題纔算是達到了自定義View的設計目的。






用在View設計的模式:


用在View上的設計模式是不少的,下面列舉一些比較經常使用的模式供你們瞭解學習。


一、設配器模式




對於android開發者來講起,適配器模式簡直太熟悉不過,有不少應用能夠說是每天在直接或者間接的用到適配器模式,好比ListView。

ListView用於顯示列表數據,可是做爲列表數據集合有不少形式,有Array,有Cursor,咱們須要對應的適配器做爲橋樑,處理相應的數據(並能造成ListView所須要的視圖)。

正是由於定義了這些適配器接口和適配器類,才能使咱們的數據簡單靈活而又正確的顯示到了adapterview的實現類上。


目的:

適配器模式,把一個類的接口變換成客戶端所期待的另外一種接口,從而使本來不匹配而沒法在一塊兒工做的兩個類可以在一塊兒工做。

適配器模式分爲類適配器模式和對象適配器模式。

關於類適配器模式,由於java的單繼承,若是繼承一個類,另外的則只能是接口,須要手動實現相應的方法。



二、組合模式


Android中對組合模式的應用,可謂是氾濫成粥,隨處可見,那就是View和ViewGroup類的使用。在android UI設計,幾乎全部的widget和佈局類都依靠這兩個類。

組合模式,Composite Pattern,是一個很是巧妙的模式。幾乎全部的面向對象系統都應用到了組合模式。


目的:

將對象View和ViewGroup組合成樹形結構以表示"部分-總體"的層次結構(View能夠作爲ViewGroup的一部分)。

組合模式使得用戶對單個對象View和組合對象ViewGroup的使用具備一致性。


三、MVC模式




MVC是三個單詞的縮寫,分別爲: 模型(Model),視圖(View)和控制Controller)。 MVC模式的目的就是實現Web系統的職能分工。 Model層實現系統中的業務邏輯。 View層用於與用戶的交互。 Controller層是Model與View之間溝通的橋樑,它能夠分派用戶的請求並選擇恰當的視圖以用於顯示,同時它也能夠解釋用戶的輸入並將它們映射爲模型層可執行的操做。



1) 視圖層(View):通常採用XML文件進行界面的描述,使用的時候能夠很是方便的引入。固然,如何你對Android瞭解的比較的多了話,就必定能夠想到在Android中也可使用JavaScript+HTML等的方式做爲View層,固然這裏須要進行Java和JavaScript之間的通訊,幸運的是,Android提供了它們之間很是方便的通訊實現。     


2) 控制層(Controller):Android的控制層的重任一般落在了衆多的Acitvity的肩上,這句話也就暗含了不要在Acitivity中寫代碼,要經過Activity交割Model業務邏輯層處理,這樣作的另一個緣由是Android中的Acitivity的響應時間是5s,若是耗時的操做放在這裏,程序就很容易被回收掉。



3) 模型層(Model):對數據庫的操做、對網絡等的操做都應該在Model裏面處理,固然對業務計算等操做也是必須放在的該層的。就是應用程序中二進制的數據。


四、MVP模式



MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示。做爲一種新的模式,MVP與MVC有着一個重大的區別:在MVP中View並不直接使用Model,它們之間的通訊是經過Presenter (MVC中的Controller)來進行的,全部的交互都發生在Presenter內部,而在MVC中View會從直接Model中讀取數據而不是經過 Controller。



在MVP模式裏一般包含4個要素:


(1)View:負責繪製UI元素、與用戶進行交互(在Android中體現爲Activity);



(2)View interface:須要View實現的接口,View經過View interface與Presenter進行交互,下降耦合,方便進行單元測試;



(3)Model:負責存儲、檢索、操縱數據(有時也實現一個Model interface用來下降耦合);



(4)Presenter:做爲View與Model交互的中間紐帶,處理與用戶交互的負責邏輯。



核心思想:

看了這麼多模式,看到頭都暈了,我都沒耐性看咯。好啦,我來解說一下吧!


其實這麼多的模式都有這樣的一個核心思想,瞭解了這個思想以後這些模式不過是同一個思想的不一樣實現罷了。



一、物理分離

將處理業務邏輯、UI佈局、數據存儲的代碼進行物理分離,分別放在不一樣的文件中。



二、外部調用

不一樣的層之間交互必定是經過調用層的開放方法來實現,好比邏輯層不會調用UI層(view類)的父類方法,而是調用其自定義方法。



三、低耦合




最後:



最後,但願你們廣開金口,聊聊本身對自定義view的看法,或者對模式的理解。但願你們能夠分享,若是文章有錯也但願能夠指正。

相關文章
相關標籤/搜索