本文轉載自: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)經過XML爲View註冊屬性。與Android提供的標準屬性寫法同樣。
例如:
須要自定義屬性Text,Select和Src,先建立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的看法,或者對模式的理解。但願你們能夠分享,若是文章有錯也但願能夠指正。