【Android 控件架構】詳解Android控件架構與常用坐標系

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

前言

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

Android控件框架

在Android的世界中View是所有控件的基類(祖宗),其中也包括ViewGroup在內。View是一個抽象的概念,特指界面中的某一個控件。而ViewGroup是代表著控件的集合,其中可以包含多個View控件,并管理他們。從某種角度上來講Android中的控件可以分為兩大類:View與ViewGroup。通過ViewGroup,整個界面的控件形成了一個樹形結構,這也就是我們常說的控件樹,上層的控件要負責測量與繪制下層的控件,并傳遞交互事件。我們在開發中常常使用到的findViewById()方法,就是在控件樹中進行深度遍歷來查找對應元素的。在每棵控件樹的頂部都存在著一個ViewParent對象,它是整棵控件樹的核心所在,所有的交互管理事件都由它來統一調度和分配,從而對整個視圖進行整體控制。

View樹結構圖

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


UI界面架構圖

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



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

插播: requestWindowFeature(Window.FEATURE_NO_TITLE) 與 setContentView() 調用順序的關系

在設置setContentView()方法之前我們可以通過requestWindowFeature(Window.FEATURE_NO_TITLE)方法設置標簽來顯示全屏。如果你看了Activity源碼中的setContentVeiw()方法你會發現,當setContentView()一旦調用,ContentView布局與TitleView會同時被加載,加載之后在調用requestWindowFeature(Window.FEATURE_NO_TITLE)方法設置標簽已經沒有作用了。所以只有在setContentView()方法之前設置標簽才能剔除TitleView達到ContentView占據全屏的效果。

視圖樹

當Acitivity的生命周期中,當onCreate()方法中調用setContentView方法后,ActivityManagerService(AMS)會調用onResume()方法,此時系統才會把整個DecorView添加到PhoneWindow中顯示出來,至此界面回執完成。

貼一張圖匯總一下吧

總結

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

Android的常用坐標系

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

1,世界坐標系

在Android的世界中,屏幕的左上角定點作為世界坐標系的原點,從這個原點水平向右為X軸正方向,原點垂直向下為Y軸正反向。

一言不合就上圖

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

1.1,世界坐標系中屏幕區域的劃分

圖片來自工匠若水博客

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

//獲取屏幕區域的寬高等尺寸獲取
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int widthPixels = metrics.widthPixels;
int heightPixels = metrics.heightPixels;
//應用程序App區域寬高等尺寸獲取
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
//獲取狀態欄高度
Rect rect= new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rectangle.top;
//View布局區域寬高等尺寸獲取
Rect rect = new Rect();  
getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(rect);  

注意:

這些方法最好都在Activity的onWindowFocusChanged() 方法之后調用,因為在Activity的聲明周期中 onCreate、onStar、 onResume這些方法都不是界面visible的真正時刻,真正的visible是在onWindowFocusChanged()方法執行時才被執行的。(onWindowFocusChanged()是在onResume()之后調用的,所以有的文章也會說是onResume()之后調用,其實更加準確的是在onWindowFocusChanged()之后,此處我會在以后的文章中做詳細介紹)

2,視圖坐標系

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

QQ截圖20170801223001.png

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

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

視圖坐標方法概述

簡單的總結一下:

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

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

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

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

注意:

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

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

View寬高方法 解釋
getWidth() layout后有效,返回值是mRight-mLeft,一般會參考measure的寬度(measure可能沒用),但不是必須的。
getHeight() layout后有效,返回值是mBottom-mTop,一般會參考measure的高度(measure可能沒用),但不是必須的。
getMeasuredWidth() 返回measure過程得到的mMeasuredWidth值,供layout參考,或許沒用。
getMeasuredHeight() 返回measure過程得到的mMeasuredHeight值,供layout參考,或許沒用。

參考:

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

《Android群英傳第三章》
Android中的坐標系以及獲取坐標的方法
Android應用坐標系統全面詳解

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評論 6 540
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,275評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,368評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,736評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,919評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,481評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,235評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,427評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,656評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,160評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,380評論 2 379

推薦閱讀更多精彩內容

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