Android
提供了一個復雜而強大的組件化模型凿可,用于構(gòu)建UI蕾盯,基于基本布局類:View
和ViewGroup
仁连。
首先,該平臺包括各種預構(gòu)建的View
和ViewGroup
子類 - 分別稱為小部件和布局 - 可用于構(gòu)建UI
径簿。
如果預構(gòu)建的小部件或布局都不符合您的需求,您可以創(chuàng)建自己的View子類嘀韧。如果您只需要對現(xiàn)有窗口小部件或布局進行小的調(diào)整篇亭,則可以簡單地對窗口小部件或布局進行子類化并覆蓋其方法。
創(chuàng)建自己的View
子類可以精確控制屏幕元素的外觀和功能锄贷。要了解自定義視圖所獲得的控件译蒂,下面是一些可以使用它們執(zhí)行操作的示例:
您可以創(chuàng)建一個完全自定義渲染的視圖類型,例如使用2D圖形渲染的“音量控制”旋鈕谊却,類似于模擬電子控件柔昼。
您可以將一組View組件組合成一個新的單個組件,可能是為了制作類似
ComboBox
(彈出列表和自由輸入文本字段的組合)炎辨,雙窗格選擇器控件(左側(cè)和右側(cè)窗格捕透,其中包含一個列表) 每個你可以重新分配哪個項目在哪個列表中),等等。您可以覆蓋
EditText
組件在屏幕上呈現(xiàn)的方式(Notepad Tutorial
使用它可以很好地創(chuàng)建帶襯里的記事本頁面)乙嘀。您可以捕獲其他事件末购,如按鍵,并以某種自定義方式處理它們(例如游戲)虎谢。
以下部分介紹了如何創(chuàng)建自定義視圖并在應用程序中使用它們盟榴。 有關詳細參考信息,請參閱View類婴噩。
一擎场、基本方法
以下是開始創(chuàng)建自己的View
組件時需要了解的內(nèi)容的高級概述:
使用您自己的類擴展現(xiàn)有的
View
類或子類。覆蓋超類中的一些方法几莽。 要覆蓋的超類方法以
'on'
開頭顶籽,例如onDraw()
,onMeasure()
和onKeyDown()
银觅。 這類似于您為生命周期和其他功能掛鉤覆蓋的Activity
或ListActivity
中的on ...
事件礼饱。
3、使用新的擴展類究驴。 完成后镊绪,可以使用新的擴展類來代替它所基于的視圖。
提示:擴展類可以定義為使用它們的活動內(nèi)部的內(nèi)部類洒忧。 這很有用蝴韭,因為它控制對它們的訪問但不是必需的(可能您希望創(chuàng)建一個新的公共視圖以便在您的應用程序中更廣泛地使用)。
二熙侍、完全定制的組件
完全自定義的組件可用于創(chuàng)建您想要的圖形組件榄鉴。 也許是一個圖形VU表,看起來像一個舊的模擬儀表蛉抓,或一個長長的文本視圖庆尘,其中彈跳球沿著單詞移動,所以你可以與卡拉OK機一起唱歌巷送。 無論哪種方式驶忌,無論你如何組合它們,你都需要內(nèi)置組件不會做的事情笑跛。
幸運的是付魔,您可以輕松地以您喜歡的任何方式創(chuàng)建外觀和行為的組件,可能僅限于您的想象力飞蹂,屏幕大小和可用處理能力(請記住几苍,最終您的應用程序可能必須運行在顯著更少的東西上 功率比您的桌面工作站)。
要創(chuàng)建完全自定義的組件:
您可以擴展的最通用的視圖陈哑,不出所料妻坝,
View
妖胀,所以您通常會首先擴展它以創(chuàng)建新的超級組件。您可以提供一個可以從
XML
獲取屬性和參數(shù)的構(gòu)造函數(shù)惠勒,您也可以使用自己的屬性和參數(shù)(可能是VU表的顏色和范圍,或者針的寬度和阻尼等)爬坑。您可能希望在組件類中創(chuàng)建自己的事件偵聽器纠屋,屬性訪問器和修改器,以及可能更復雜的行為盾计。
您幾乎肯定想要覆蓋
onMeasure()
售担,如果您希望組件顯示某些東西,也可能需要覆蓋onDraw()
署辉。 雖然兩者都有默認行為族铆,但默認的onDraw()
將不執(zhí)行任何操作,默認的onMeasure()
將始終設置為100x100的大小 - 這可能不是您想要的哭尝。其他
on ...
方法也可以根據(jù)需要覆蓋哥攘。
擴展onDraw()和onMeasure()
onDraw()
方法為您提供了一個Canvas
,您可以在其上實現(xiàn)任何您想要的東西:2D圖形材鹦,其他標準或自定義組件逝淹,樣式文本或您能想到的任何其他內(nèi)容。
注意:這不適用于3D圖形桶唐。 如果要使用3D圖形栅葡,則必須擴展SurfaceView而不是View,并從單獨的線程中繪制尤泽。 有關詳細信息欣簇,請參閱GLSurfaceViewActivity示例。
onMeasure()
更多涉及坯约。onMeasure()
是組件與其容器之間的渲染合同的關鍵部分熊咽。 應該重寫onMeasure()
以高效準確地報告其包含部分的測量值。 根據(jù)父級的限制要求(傳入onMeasure()
方法)以及一旦計算出的測量寬度和高度調(diào)用setMeasuredDimension()
方法的要求闹丐,這會稍微復雜一些网棍。 如果您未能從重寫的onMeasure()
方法調(diào)用此方法,則結(jié)果將是測量時的異常妇智。
在較高的層次上滥玷,實現(xiàn)onMeasure()
看起來像這樣:
使用寬度和高度測量規(guī)范(
widthMeasureSpec
和heightMeasureSpec
參數(shù),都是表示尺寸的整數(shù)代碼)調(diào)用重寫的onMeasure()
方法巍棱,應將其視為對應生成的寬度和高度測量的限制的要求惑畴。 可以在View.onMeasure(int,int)
下的參考文檔中找到這些規(guī)范可能需要的限制的完整參考(此參考文檔也非常好地解釋了整個測量操作)航徙。組件的
onMeasure()
方法應計算渲染組件所需的測量寬度和高度如贷。 它應該盡量保持在傳入的規(guī)范內(nèi),盡管它可以選擇超過它們(在這種情況下,父級可以選擇做什么杠袱,包括剪切尚猿,滾動,拋出異常楣富,或者讓onMeasure()
再試一次凿掂, 也許有不同的測量規(guī)格)。計算寬度和高度后纹蝴,必須使用計算的測量值調(diào)用
setMeasuredDimension(int width庄萎,int height)
方法。 如果不這樣做將導致拋出異常塘安。
三糠涛、復合控制
如果您不想創(chuàng)建完全自定義的組件,而是希望將由一組現(xiàn)有控件組成的可重用組件放在一起兼犯,那么創(chuàng)建復合組件(或復合控件)可能符合要求忍捡。 簡而言之,這將更多原子控件(或視圖)集合到一個邏輯組項中切黔,這些項可以作為單個事物處理锉罐。 例如,組合框可以被認為是單行EditText
字段和具有附加PopupList
的相鄰按鈕的組合绕娘。 如果按下按鈕并從列表中選擇一些內(nèi)容脓规,它會填充EditText
字段,但如果用戶愿意险领,用戶也可以直接在EditText
中輸入內(nèi)容侨舆。
在Android
中,實際上有兩個其他視圖可供使用:Spinner
和AutoCompleteTextView
绢陌,但無論如何挨下,組合框的概念是一個易于理解的例子。
要創(chuàng)建復合組件:
通常的起點是某種布局脐湾,因此創(chuàng)建一個擴展布局的類臭笆。 也許在組合框的情況下,我們可能使用具有水平方向的
LinearLayout
秤掌。 請記住愁铺,其他布局可以嵌套在內(nèi)部,因此復合組件可以是任意復雜和結(jié)構(gòu)化的闻鉴。 請注意茵乱,就像使用Activity
一樣,您可以使用聲明式(基于XML
)方法來創(chuàng)建包含的組件孟岛,也可以從代碼中以編程方式嵌套它們瓶竭。在新類的構(gòu)造函數(shù)中督勺,獲取超類所需的任何參數(shù),并首先將它們傳遞給超類構(gòu)造函數(shù)斤贰。 然后智哀,您可以設置其他視圖以在新組件中使用; 這是您創(chuàng)建
EditText
字段和PopupList
的位置。 請注意荧恍,您還可以在XML
中引入自己的屬性和參數(shù)瓷叫,這些屬性和參數(shù)可以由構(gòu)造函數(shù)提取和使用。您還可以為包含的視圖可能生成的事件創(chuàng)建偵聽器块饺,例如,
List Item
的偵聽器方法單擊Listener
以在創(chuàng)建列表時更新EditText
的內(nèi)容雌芽。您還可以使用訪問器和修飾符創(chuàng)建自己的屬性授艰,例如,允許在組件中最初設置EditText值世落,并在需要時查詢其內(nèi)容淮腾。
在擴展布局的情況下,您不需要覆蓋
onDraw()
和onMeasure()
方法屉佳,因為布局將具有可能正常工作的默認行為谷朝。 但是,如果需要武花,您仍然可以覆蓋它們圆凰。你可以覆蓋其他
on ...
方法,比如onKeyDown()
体箕,或者在按下某個鍵時從組合框的彈出列表中選擇某些默認值专钉。
總而言之,使用布局作為自定義控件的基礎具有許多優(yōu)點累铅,包括:
您可以使用聲明性
XML
文件指定布局跃须,就像使用活動屏幕一樣,或者您可以以編程方式創(chuàng)建視圖并將它們嵌入到代碼的布局中娃兽。onDraw()
和onMeasure()
方法(以及其他大多數(shù)on ......方法)可能具有合適的行為菇民,因此您不必覆蓋它們。最后投储,您可以非车诹罚快速地構(gòu)造任意復雜的復合視圖,并將它們重新使用玛荞,就像它們是單個組件一樣复旬。
四、修改現(xiàn)有視圖類型
創(chuàng)建自定義視圖有一個更簡單的選項冲泥,這在某些情況下很有用驹碍。 如果某個組件已經(jīng)非常類似于您想要的組件壁涎,則只需擴展該組件并覆蓋您想要更改的行為即可。 您可以使用完全自定義的組件執(zhí)行所有操作志秃,但是從View層次結(jié)構(gòu)中的更專業(yè)的類開始怔球,您還可以免費獲得許多可能完全符合您需要的行為。
作為示例浮还,NotePad
應用程序演示了使用Android
平臺的許多方面竟坛。 其中包括擴展EditText
視圖以制作帶襯里的記事本。 這不是一個完美的例子钧舌,用于這樣做的API
可能會改變担汤,但它確實證明了這些原則。
如果您還沒有這樣做洼冻,請將NotePad
示例導入Android Studio
(或者使用提供的鏈接查看源代碼)崭歧。 特別要注意NoteEditor.java
文件中LinedEditText
的定義。
以下是此文件中需要注意的事項:
- 定義
該類定義如下:
public static class LinedEditText extends EditText
LinedEditText
被定義為NoteEditor
活動中的內(nèi)部類撞牢,但它是公共的率碾,因此如果需要,它可以從NoteEditor
類的外部作為NoteEditor.LinedEditText
訪問屋彪。它是靜態(tài)的所宰,這意味著它不會生成允許它從父類訪問數(shù)據(jù)的所謂“合成方法”,這反過來意味著它實際上表現(xiàn)為一個單獨的類而不是與
NoteEditor
強烈相關的東西畜挥。 如果它們不需要從外部類訪問狀態(tài)仔粥,保持生成的類很小,并允許從其他類中輕松使用它蟹但,那么這是創(chuàng)建內(nèi)部類的更簡潔方法件炉。它擴展了
EditText
,這是我們在這種情況下選擇自定義的View
矮湘。 完成后斟冕,新類將能夠替換正常的EditText視圖。
- 類初始化
與往常一樣缅阳,超級首先被稱為磕蛇。 此外,這不是默認構(gòu)造函數(shù)十办,而是參數(shù)化構(gòu)造函數(shù)秀撇。 當EditText
從XML
布局文件中膨脹時,會使用這些參數(shù)創(chuàng)建EditText
向族,因此呵燕,我們的構(gòu)造函數(shù)需要同時接受它們并將它們傳遞給超類構(gòu)造函數(shù)。
- 重寫方法
此示例僅覆蓋一個方法onDraw()
件相,但您可能需要在創(chuàng)建自己的自定義組件時覆蓋其他方法再扭。
對于此示例氧苍,重寫onDraw()
方法允許我們在EditText視圖畫布上繪制藍線(畫布將傳遞到重寫的onDraw()
方法)。 在方法結(jié)束之前調(diào)用super.onDraw()
方法泛范。 應該調(diào)用超類方法让虐,在這種情況下,我們在繪制了要包含的行之后最后執(zhí)行它罢荡。
- 使用自定義組件
我們現(xiàn)在有自定義組件赡突,但我們?nèi)绾问褂盟?在NotePad
示例中,自定義組件直接從聲明性布局中使用区赵,因此請查看res / layout
文件夾中的note_editor.xml
惭缰。
<view xmlns:android="http://schemas.android.com/apk/res/android"
class="com.example.android.notepad.NoteEditor$LinedEditText"
android:id="@+id/note"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:padding="5dp"
android:scrollbars="vertical"
android:fadingEdge="vertical"
android:gravity="top"
android:textSize="22sp"
android:capitalize="sentences"
/>
- 自定義組件在
XML
中創(chuàng)建為通用視圖,并使用完整包指定類笼才。 另請注意漱受,我們定義的內(nèi)部類是使用NoteEditor $ LinedEditText
表示法引用的,這是一種在Java
編程語言中引用內(nèi)部類的標準方法患整。
如果未將自定義View
組件定義為內(nèi)部類拜效,則可以使用XML元素名稱聲明View組件喷众,并排除class
屬性各谚。 例如:
<com.example.android.notepad.LinedEditText
id="@+id/note"
... />
請注意,LinedEditText
類現(xiàn)在是一個單獨的類文件到千。 當類嵌套在NoteEditor
類中時昌渤,此技術將不起作用。
- 定義中的其他屬性和參數(shù)是傳遞給自定義組件構(gòu)造函數(shù)的屬性和參數(shù)憔四,然后傳遞給EditText構(gòu)造函數(shù)膀息,因此它們與用于EditText視圖的參數(shù)相同。 請注意了赵,也可以添加自己的參數(shù)潜支,我們將在下面再次討論。
這就是它的全部柿汛。 不可否認冗酿,這是一個簡單的案例,但重點是 - 創(chuàng)建自定義組件只是你需要的那么復雜络断。
更復雜的組件可能會覆蓋更多on ...方法并引入一些自己的輔助方法裁替,從根本上定制其屬性和行為。 唯一的限制是你的想象力以及你需要組件做什么貌笨。