【Android 控件架構(gòu)】詳解Android控件架構(gòu)與常用坐標(biāo)系

【本文出自大圣代的技術(shù)專欄 http://blog.csdn.net/qq_23191031
【轉(zhuǎn)載煩請注明出處杯道,尊重他人勞動成果就是對您自己的尊重】

前言

View在Android的世界中扮演著重要的角色,正是這些控件組成了一個又一個精美的App。View體系是Android界面編程的核心,雖然它不屬于四大組件但是它的重要行卻毫不遜色,這個系列我會陸續(xù)從View的滑動事件、View 的事件反饋、自定義View等多個方面逐步介紹Android View體系痛垛。如果能幫助到你,那是我莫大的榮幸桶蛔。

Android控件框架

在Android的世界中View是所有控件的基類(祖宗)匙头,其中也包括ViewGroup在內(nèi)。View是一個抽象的概念仔雷,特指界面中的某一個控件蹂析。而ViewGroup是代表著控件的集合舔示,其中可以包含多個View控件,并管理他們电抚。從某種角度上來講Android中的控件可以分為兩大類:View與ViewGroup惕稻。通過ViewGroup,整個界面的控件形成了一個樹形結(jié)構(gòu)蝙叛,這也就是我們常說的控件樹俺祠,上層的控件要負責(zé)測量與繪制下層的控件,并傳遞交互事件借帘。我們在開發(fā)中常常使用到的findViewById()方法锻煌,就是在控件樹中進行深度遍歷來查找對應(yīng)元素的。在每棵控件樹的頂部都存在著一個ViewParent對象姻蚓,它是整棵控件樹的核心所在,所有的交互管理事件都由它來統(tǒng)一調(diào)度和分配匣沼,從而對整個視圖進行整體控制狰挡。

View樹結(jié)構(gòu)圖

在每一個Activity中都包含了一個Window,而這個Window通常上是由PhoneWindow實現(xiàn)的释涛,而PhoneWindow又將DecorView設(shè)置為整個界面的根布局加叁,DecorView作為根布局將要顯示的具體內(nèi)容呈現(xiàn)在PhoneWindow上,并提供了一些通用方法來操作界面唇撬。這里所有View的交互事件都由WindowManagerService(WMS)進行接收它匕,并通過Activity回調(diào)相應(yīng)的onClickListener。


UI界面架構(gòu)圖

在上面的視圖上我們可以看到此時屏幕被分成了兩部分:TitleView與ContentView窖认。如圖紅色的區(qū)域就是ContentView豫柬,contentView是一個ID為content的Framelayou這也是我們通過布局文件可以控制的區(qū)域,實際上我們所有的布局都設(shè)置在這樣的Fragmelayout中扑浸。



這也就是為什么Activity烧给、Fragment中設(shè)置根布局的方法叫做setContentView了。

插播: requestWindowFeature(Window.FEATURE_NO_TITLE) 與 setContentView() 調(diào)用順序的關(guān)系

在設(shè)置setContentView()方法之前我們可以通過requestWindowFeature(Window.FEATURE_NO_TITLE)方法設(shè)置標(biāo)簽來顯示全屏喝噪。如果你看了Activity源碼中的setContentVeiw()方法你會發(fā)現(xiàn)础嫡,當(dāng)setContentView()一旦調(diào)用,ContentView布局與TitleView會同時被加載酝惧,加載之后在調(diào)用requestWindowFeature(Window.FEATURE_NO_TITLE)方法設(shè)置標(biāo)簽已經(jīng)沒有作用了榴鼎。所以只有在setContentView()方法之前設(shè)置標(biāo)簽才能剔除TitleView達到ContentView占據(jù)全屏的效果。

視圖樹

當(dāng)Acitivity的生命周期中晚唇,當(dāng)onCreate()方法中調(diào)用setContentView方法后巫财,ActivityManagerService(AMS)會調(diào)用onResume()方法,此時系統(tǒng)才會把整個DecorView添加到PhoneWindow中顯示出來哩陕,至此界面回執(zhí)完成翁涤。

貼一張圖匯總一下吧

總結(jié)

更詳細的說明請參見【Android View源碼分析(一)】setContentView加載視圖機制深度分析

Android的常用坐標(biāo)系

在Android的世界中我們最常用到的就是Android坐標(biāo)系(我認為稱為世界坐標(biāo)系更準(zhǔn)確)和視圖坐標(biāo)系了桥言。對于一個控件而言,它在Android世界坐標(biāo)系中的位置我們可以稱之為:絕對坐標(biāo)系葵礼;而在視圖坐標(biāo)系中号阿,指示的就是它的相對位置了。下面我們就來分析一下他們吧

1鸳粉,世界坐標(biāo)系

在Android的世界中扔涧,屏幕的左上角定點作為世界坐標(biāo)系的原點,從這個原點水平向右為X軸正方向届谈,原點垂直向下為Y軸正反向枯夜。

一言不合就上圖

Android系統(tǒng)中為我們提供了getLocationOnScreen(int[] location)方法來獲取控件在整個屏幕的絕對坐標(biāo),此時要注意的是:該坐標(biāo)是從屏幕的左上角(原點)開始獲取的艰山,所以也包括了狀態(tài)欄的高度湖雹,如下圖。

1.1曙搬,世界坐標(biāo)系中屏幕區(qū)域的劃分

圖片來自工匠若水博客

通過上圖我們可以很直觀的看到Android的屏幕區(qū)域是如何劃分的摔吏。接下來我們就看看如何或者這些區(qū)域中的坐標(biāo)和度量方法吧。

//獲取屏幕區(qū)域的寬高等尺寸獲取
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
//應(yīng)用程序App區(qū)域?qū)捀叩瘸叽绔@取
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
//獲取狀態(tài)欄高度
Rect rect= new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rectangle.top;
//View布局區(qū)域?qū)捀叩瘸叽绔@取
Rect rect = new Rect();  
getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);  

注意:

這些方法最好都在Activity的onWindowFocusChanged() 方法之后調(diào)用纵装,因為在Activity的聲明周期中 onCreate征讲、onStar、 onResume這些方法都不是界面visible的真正時刻橡娄,真正的visible是在onWindowFocusChanged()方法執(zhí)行時才被執(zhí)行的诗箍。(onWindowFocusChanged()是在onResume()之后調(diào)用的,所以有的文章也會說是onResume()之后調(diào)用,其實更加準(zhǔn)確的是在onWindowFocusChanged()之后挽唉,此處我會在以后的文章中做詳細介紹)

2滤祖,視圖坐標(biāo)系

在日常開發(fā)中我們接觸最對的就是視圖坐標(biāo)系了,視圖坐標(biāo)系描述的是子控件在父控件中相對位置瓶籽。貼一張圖來說明一下

QQ截圖20170801223001.png

所謂視圖坐標(biāo)系是以控件(例如圖中的TextView)父視圖(圖中的ViewGroup))的左上角為坐標(biāo)原點的(綠色部分)氨距,從原出發(fā)水平向右為x軸正方向,垂直向下為y軸正方向來表示控件的相對位置的棘劣。

那么這個相對位置到底如何表示呢俏让,同樣看圖說話。

視圖坐標(biāo)方法概述

簡單的總結(jié)一下:

View提供的獲取坐標(biāo)方法
通過如下方法可以獲得View到其父控件(ViewGroup)的距離:

方法 解釋
getTop() 獲取View自身頂邊到其父布局頂邊的距離
getLeft() 獲取View自身左邊到其父布局左邊的距離
getRight() 獲取View自身右邊到其父布局左邊的距離
getBottom() 獲取View自身底邊到其父布局頂邊的距離
getX() 返回值為getLeft()+getTranslationX()茬暇,當(dāng)setTranslationX()時getLeft()不變首昔,getX()變。
getY() 返回值為getTop()+getTranslationY()糙俗,當(dāng)setTranslationY()時getTop()不變勒奇,getY()變。

MotionEvent提供的獲取坐標(biāo)方法
我們看上圖那個觸摸點巧骚,我們知道無論是View還是ViewGroup赊颠,最終的點擊事件都會由onTouchEvent(MotionEvent event)方法來處理格二,MotionEvent也提供了各種獲取焦點坐標(biāo)的方法:

方法 解釋
getX() 獲取點擊事件距離控件左邊的距離,即視圖坐標(biāo)
getY() 獲取點擊事件距離控件頂邊的距離竣蹦,即視圖坐標(biāo)
getRawX() 獲取點擊事件距離整個屏幕左邊距離顶猜,即絕對坐標(biāo)
getRawY() 獲取點擊事件距離整個屏幕頂邊的的距離,即絕對坐標(biāo)

注意:

View中的getX()痘括、getY()方法只是與MotionEvent中的getX()长窄、getY()方法只是重名而已,并不是一個纲菌。

上面就解釋了你在很多代碼中看見各種getXXX方法進行數(shù)學(xué)邏輯運算判斷的含義挠日。不過上面只是說了一些相對靜止的世界坐標(biāo)點關(guān)系,下面我們來看看幾個和上面方法緊密相關(guān)的View方法翰舌,此處在本篇文章中不是重點嚣潜,我會在以后的文章中做詳細講解。:

View寬高方法 解釋
getWidth() layout后有效椅贱,返回值是mRight-mLeft懂算,一般會參考measure的寬度(measure可能沒用),但不是必須的夜涕。
getHeight() layout后有效,返回值是mBottom-mTop属愤,一般會參考measure的高度(measure可能沒用)女器,但不是必須的。
getMeasuredWidth() 返回measure過程得到的mMeasuredWidth值住诸,供layout參考驾胆,或許沒用。
getMeasuredHeight() 返回measure過程得到的mMeasuredHeight值贱呐,供layout參考丧诺,或許沒用。

參考:

如果說我比別人看得更遠些,那是因為我站在了巨人的肩上

《Android群英傳第三章》
Android中的坐標(biāo)系以及獲取坐標(biāo)的方法
Android應(yīng)用坐標(biāo)系統(tǒng)全面詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奄薇,一起剝皮案震驚了整個濱河市驳阎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馁蒂,老刑警劉巖呵晚,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沫屡,居然都是意外死亡饵隙,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門沮脖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來金矛,“玉大人芯急,你說我怎么就攤上這事∈豢。” “怎么了娶耍?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長废睦。 經(jīng)常有香客問我伺绽,道長,這世上最難降的妖魔是什么嗜湃? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任奈应,我火速辦了婚禮,結(jié)果婚禮上购披,老公的妹妹穿的比我還像新娘杖挣。我一直安慰自己,他們只是感情好刚陡,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布惩妇。 她就那樣靜靜地躺著,像睡著了一般筐乳。 火紅的嫁衣襯著肌膚如雪歌殃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天蝙云,我揣著相機與錄音氓皱,去河邊找鬼。 笑死勃刨,一個胖子當(dāng)著我的面吹牛波材,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播身隐,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼廷区,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贾铝?” 一聲冷哼從身側(cè)響起隙轻,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎垢揩,沒想到半個月后大脉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡水孩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年镰矿,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俘种。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡秤标,死狀恐怖绝淡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苍姜,我是刑警寧澤牢酵,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站衙猪,受9級特大地震影響馍乙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜垫释,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一丝格、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棵譬,春花似錦显蝌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至脏嚷,卻和暖如春骆撇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背父叙。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工神郊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人高每。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓屿岂,卻偏偏與公主長得像践宴,于是被迫代替她去往敵國和親鲸匿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,848評論 25 707
  • Android控件架構(gòu)與自定義控件(一) (本文并非原創(chuàng)文章阻肩,整理摘抄方便自己查看带欢,原文地址為Android控件架...
    b5e7a6386c84閱讀 969評論 0 6
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,375評論 0 17
  • 提到自由兩個字總是會引起許多的的遐想烤惊,而二十歲又恰好是一個富有朝氣乔煞,又不失理智的年齡。這個年齡的我們應(yīng)該做些什么柒室?...
    丿肆悅閱讀 710評論 9 5
  • 老街對于我們來說還有另一個名字我渡贾,那就是美食一條街。街上從頭到尾處處是小賣部雄右,基本上每走五六米就能看到一家空骚,并且越...
    ___hh閱讀 398評論 0 3