《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 其他 > 設(shè)計(jì)應(yīng)用 > 深入理解Android 之界面構(gòu)造
深入理解Android 之界面構(gòu)造
Venus神廟的博客
摘要: 對(duì)于開(kāi)發(fā)者來(lái)說(shuō),鍛造這樣的面容,,不但需要高超的技藝,,也需要有稱手的工具和對(duì)得起黨的料子。俗話說(shuō),,朽木不可雕也,,芙蓉不是一日煉成的,不是什么平臺(tái)都能叫特能書(shū),。
關(guān)鍵詞: Android UI
Abstract:
Key words :

  UI" title="UI">UI界面,,對(duì)于每個(gè)應(yīng)用而言,是它與用戶進(jìn)行交互的門(mén)臉,。好的門(mén)臉,,不只是是要亮麗可人,最好還能秀色可餐過(guò)目不忘,,甚至還應(yīng)該有涵養(yǎng)有氣質(zhì),,彬彬有理溫柔耐心。

  對(duì)于開(kāi)發(fā)者來(lái)說(shuō),,鍛造這樣的面容,,不但需要高超的技藝,也需要有稱手的工具和對(duì)得起黨的料子,。俗話說(shuō),,朽木不可雕也,芙蓉不是一日煉成的,,不是什么平臺(tái)都能叫特能書(shū),。有套好用的UI框架,對(duì)于開(kāi)發(fā)者而言,,真有如沙漠中的甘露,,而要是撞見(jiàn)了杯具的UI套件,整個(gè)界面開(kāi)發(fā)就有如夢(mèng)魘了,。

  Android" title="Android">Android的UI框架,,最核心的,是資源和Layout體系,,然后,,通過(guò)完善的控件庫(kù),簡(jiǎn)明的接口設(shè)計(jì),,進(jìn)一步幫助開(kāi)發(fā)者,,能夠最快的搭建自己需要界面(聽(tīng)到這里,Symbian同學(xué)開(kāi)始鉆土,。..),。

  UI控件

  做UI,有時(shí)候就像搭積木,,在Android中,,這個(gè)最原子的積木塊,就是View,。所有其他的UI元素,,都是派生于此類的子孫類們,。

  

  又從SDK中偷來(lái)張圖,用來(lái)描述Android的UI控件結(jié)構(gòu),,在每一個(gè)window下,這都是一個(gè)標(biāo)準(zhǔn)而完整的樹(shù)結(jié)構(gòu),。View有一個(gè)子類ViewGroup,,它相當(dāng)于一個(gè)容器類或者是復(fù)合控件,所有派生與ViewGroup的子類在這顆UI樹(shù)中都可以承擔(dān)著父節(jié)點(diǎn)的職責(zé),,而另一些繞過(guò)ViewGroup從View直通下來(lái)的,,就只能蜷局在葉節(jié)點(diǎn)的范疇內(nèi)了。

  之所有說(shuō)這是一個(gè)很標(biāo)準(zhǔn)的控件樹(shù),,是因?yàn)楦缚丶?duì)子控件有絕對(duì)的掌控權(quán),,每個(gè)子控件的占地面積和位置,都是基于父控件來(lái)分配的,,它能夠接受和處理的事件,,也是父控件派發(fā)下去的。這樣的結(jié)構(gòu),,被很多平臺(tái)和框架廣泛的認(rèn)可,,和傳統(tǒng)的win開(kāi)發(fā)和杯具的Symbian相比,雖然因?yàn)槭录鞑ネ緩阶冮L(zhǎng)了,,很多操作的效率變低了,,但整個(gè)結(jié)構(gòu)更有層次性,每個(gè)控件只需要多其父控件負(fù)責(zé)指揮子控件就好,,職責(zé)明確,,邏輯簡(jiǎn)單,利于開(kāi)發(fā)和設(shè)計(jì),。

  談及任何平臺(tái)的控件,,都有一些不可避免的主題,比如,,每個(gè)控件如何標(biāo)識(shí),,如何設(shè)定大小和位置,如何接受和處理事件,,如何繪制,,諸如此類。

  標(biāo)識(shí)

  在Android中,,你可以為每個(gè)控件選擇設(shè)定一個(gè)id,,這個(gè)id的全局的唯一性不需要保證,但在某個(gè)局部的范圍內(nèi)具有可識(shí)別性,,這樣就可以通過(guò)這個(gè)id找到這個(gè)控件(如果不需要查找,,就別設(shè)置了,。..)。

  但是,,在父控件中逐級(jí)的find比較,,找到id匹配的控件,然后再做轉(zhuǎn)型,,是一個(gè)比較重量的操作,,于是Android又為控件憋出另一個(gè)屬性,tag,。它接受任意object類型的數(shù)據(jù),,你可以把和這個(gè)控件對(duì)象相關(guān)的內(nèi)容堆在里面。比如,,在list中,,我們常常將和每個(gè)list item相關(guān)的所有控件元素封裝成一個(gè)object,扔到tag中,,就不需要每次都去比較id進(jìn)行尋找,,更加高效快捷。

  尺寸

  在Android中,,控件最重要的大小屬性,,就是width/height,開(kāi)發(fā)者可以明確的指明控件的大小,,可以設(shè)定成為fill_parent和wrap_content,,這樣的概念性的大小。丈量并設(shè)定控件的位置,,是通過(guò)兩步來(lái)進(jìn)行的,。

  第一步是measure。它傳入此控件的width/height信息,,控件會(huì)根據(jù)自己的參數(shù),,計(jì)算出真實(shí)需要的width/height,然后調(diào)用setMeasuredDimension方法,,緩存成成員變量,,留作后用。

  在計(jì)算出大小之后,,會(huì)進(jìn)行另一個(gè)步驟,,layout。在這個(gè)過(guò)程中,,父控件會(huì)計(jì)算其上各個(gè)子控件的位置,,從而完成整個(gè)大小和位置的確定流程。整個(gè)measure和layout的流程,,都是自上到下,,從樹(shù)頂往葉子來(lái)推進(jìn)的,。

  當(dāng)開(kāi)發(fā)人員需要自定義控件的時(shí)候,可能需要關(guān)注這些內(nèi)容,,通過(guò)重載onMeasure和onLayout方法,,可以定義自己控件的丈量方式。

  事件

  在Android中,,所有的按鍵,,觸屏等事件,都是從頂至下進(jìn)行分發(fā)的,。每個(gè)ViewGroup的對(duì)象,,會(huì)維系一個(gè)focused變量,,它表示在這個(gè)父控件中具備focus的控件,,當(dāng)有按鍵時(shí)間發(fā)生的時(shí)候,會(huì)找到這個(gè)focused子控件,,并傳遞給它,。同理,觸屏事件的分發(fā)也是類似,,只不過(guò)和focus無(wú)關(guān),,父控件會(huì)遍歷所有子控件,看看誰(shuí)處于觸碰位置,,從而傳遞給誰(shuí),。

  另外還有一些事件,邏輯上并不是從頂至下發(fā)起的,。比如,,當(dāng)你修改某個(gè)子控件的內(nèi)容,使得該子控件的大小和內(nèi)容都發(fā)生了變化,,就需要進(jìn)行控件的重排和重繪,,這些操作不僅是子控件自己的事情,需要整個(gè)控件樹(shù)上的所有控件都需要配合,。在Android中,,處理這類事情的實(shí)現(xiàn)策略是子控件維系一個(gè)ViewParent對(duì)象,該對(duì)象象征著整個(gè)控件樹(shù)的管理者,,子控件產(chǎn)生影響整個(gè)控件樹(shù)的事件時(shí),,會(huì)通知到ViewParent,ViewParent會(huì)將其轉(zhuǎn)換成一個(gè)自頂向下的事件,,分發(fā)下去,。

  Android的事件處理邏輯,采用的是觀察者模式,。Android的控件提供了一些列的add/set Listener的接口,,使得外部觀察者,,有機(jī)會(huì)處理控件事件。比如,,你需要在某個(gè)button被點(diǎn)擊時(shí)做一些事情,,你就需要派生一個(gè)View.OnClickListener對(duì)象作為觀察者,調(diào)用該控件的setOnClickListener接口注冊(cè)進(jìn)去,,當(dāng)button被點(diǎn)擊,,就可以獲得處理點(diǎn)擊事件的機(jī)會(huì)了。當(dāng)然,,有的時(shí)候,,你需要處理的邏輯更為復(fù)雜,光是站在外面圍觀叫好不能解決問(wèn)題,,可能就需要派生某個(gè)控件,,去重載onXXXX之類的事件處理函數(shù),進(jìn)行更完整的控制,。

  焦點(diǎn)

  對(duì)于一個(gè)非觸屏的機(jī)器,,焦點(diǎn)的維系是一個(gè)極其重要的事情,而在有觸屏的年代,,焦點(diǎn)的地位雖有所下降,,但依然還是需要妥善保護(hù)的。

  Android中,,是以控件樹(shù)為單位,,來(lái)管理焦點(diǎn)的。每個(gè)控件,,可以設(shè)置上下左右四向的focus轉(zhuǎn)移對(duì)象,。當(dāng)在一個(gè)控件上發(fā)生焦點(diǎn)轉(zhuǎn)移事件,Android會(huì)如前述,,自頂向下根據(jù)設(shè)定好的焦點(diǎn)轉(zhuǎn)移邏輯,,跳轉(zhuǎn)到正確的控件上。和Symbian相比,,真是,,真是。,。,。

  Layout

  Layout是一類特殊的ViewGroup控件,它們本身沒(méi)有任何可顯示內(nèi)容,,形如透明的玻璃盒子,,存活的唯一理由,就是其中的內(nèi)部結(jié)構(gòu),能夠更好的擺放它的子控件們,。

  比如線性的Layout,,LinearLayout。放入這個(gè)Layout的子控件,,會(huì)按水平或垂直方向,,排排坐,一個(gè)挨著一個(gè)按順序排列下去,。TableLayout,,可以將子控件按照表格的形式,一枚枚放置好,。而RelativeLayout則更靈活,,可以設(shè)定各個(gè)控件之間的對(duì)齊和排列關(guān)系,適合定制復(fù)雜的界面,。

  有了Layout的存在,,控件和控件之間不再割裂的存在,而是更有機(jī)的結(jié)合在了一起,,設(shè)定起來(lái)也更為方便,。比Symbian那樣人肉維系各個(gè)控件的關(guān)系,,輕松自在多了,。

  更多

  這些問(wèn)題的完整答案,參見(jiàn)SDK中View的頁(yè)面:/reference/android/view/View.html,。

  實(shí)現(xiàn)

  有了這些對(duì)Android的UI控件的認(rèn)知,,可以看更整體性的實(shí)現(xiàn)細(xì)節(jié),那就是Activity的UI實(shí)現(xiàn),。

  

  如上圖所示,,假設(shè)你做了個(gè)如同虛線框中結(jié)構(gòu)的一個(gè)界面,通過(guò)Activity的setContentView方法,,塞進(jìn)了Activity中,,就會(huì)形成圖示的一個(gè)邏輯關(guān)系。每一個(gè)Activity,,都包含一個(gè)Window對(duì)象,,它表示的是一個(gè)頂級(jí)的一整屏幕上面的界面邏輯。在Android源碼中,,其實(shí)現(xiàn)是MidWindow,,它包含了一個(gè)FrameLayout對(duì)象,呈現(xiàn)出來(lái)就是那種帶著一個(gè)title的界面樣子,。自定義的一堆控件,,會(huì)插進(jìn)Window的界面部分,在Activity中,,所有事件的處理邏輯,,是Window先享用,,沒(méi)消費(fèi)掉在交由這堆控件吃剩的。

  在整個(gè)控件樹(shù)的最頂端,,是一個(gè)邏輯的樹(shù)頂,,ViewParent,在源碼中的實(shí)現(xiàn)是ViewRoot,。它是整個(gè)控件樹(shù)和WindowManager之間的事件信息的翻譯者,。WindowManager是Android中一個(gè)重要的服務(wù)。它將用戶的操作,,翻譯成為指令,,發(fā)送給呈現(xiàn)在界面上的各個(gè)Window。Activity,,會(huì)將頂級(jí)的控件注冊(cè)到WindowManager中,,當(dāng)用戶真是觸碰屏幕或鍵盤(pán)的時(shí)候,WindowManager就會(huì)通知到,,而當(dāng)控件有一些請(qǐng)求產(chǎn)生,,也會(huì)經(jīng)由ViewParent送回到WindowManager中。從而完成整個(gè)通信流程,。

此內(nèi)容為AET網(wǎng)站原創(chuàng),,未經(jīng)授權(quán)禁止轉(zhuǎn)載。