Android中的View(控件)樹(shù)結(jié)構(gòu)

我是IT王魔王
這是我的第2篇IT原創(chuàng)

有個(gè)小伙伴面試時(shí)碰到了一個(gè)問(wèn)題:不給Activity的根視圖添加id,怎么獲取到這個(gè)View钩杰?

沒(méi)聽(tīng)明白這個(gè)問(wèn)題不要緊,我再給大家解釋一下

Activity的布局文件如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tvTest"
        android:textSize="30sp"
        android:textColor="#ffffff"
        android:text="我是Activity中的布局"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:background="@color/colorAccent" />

</RelativeLayout>

Activity中的代碼如下:

public class ViewTreeMainActivity extends AppCompatActivity {
    private static final String TAG = "ViewTreeMainActivity===";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_view_tree_main);

        findViewById(R.id.tvTest).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO: 2020/6/1 獲取布局中的根節(jié)點(diǎn) ,即本demo 布局文件中的RelativeLayout
            }
        });

    }
}

注意看TODO中需要我們實(shí)現(xiàn)的邏輯,就是面試官的問(wèn)題放刨。

如果你看懂問(wèn)題了,并且有答案了尸饺,那么你可以點(diǎn)贊離開(kāi)了进统。

如果你沒(méi)看懂問(wèn)題,但是有答案了浪听,我信了你的邪螟碎。

如果你沒(méi)看懂問(wèn)題,并且沒(méi)有答案迹栓,麻煩你再審閱一下這個(gè)問(wèn)題掉分。

如果你看懂問(wèn)題了,但是沒(méi)有答案克伊,那么你應(yīng)該繼續(xù)往下看

現(xiàn)在我揭曉答案叉抡,就兩行代碼

  FrameLayout rootView = findViewById(android.R.id.content);
  RelativeLayout relativeLayout = (LinearLayout) rootView.getChildAt(0);

如果你碰到的面試官特別水,你現(xiàn)在可以抄抄作業(yè)答毫,離開(kāi)了褥民。

記得點(diǎn)贊

悲哀的是,一般面試官會(huì)再來(lái)一句洗搂,為什么消返?

是啊载弄,為什么id要寫android.R.id.content?FrameLayout從哪里來(lái)的撵颊?

想知道這個(gè)所以然宇攻,我們就得從Android中的View(控件)樹(shù)結(jié)構(gòu)說(shuō)起

先上圖

Android中的控件樹(shù)結(jié)構(gòu).png

我們不熟悉的是紅虛線上的結(jié)構(gòu),這部分也是我們學(xué)習(xí)的重點(diǎn)倡勇。

簡(jiǎn)單解釋一下:

1逞刷、每個(gè)Activity中都有一個(gè)Window,Window用于顯示我們的界面妻熊,Activity負(fù)責(zé)管理Window夸浅。
2、每個(gè)Window都有一個(gè)根View--->DecorView扔役。Window自身并不能顯示界面帆喇,Android中真正顯示畫面得靠View。

3亿胸、DecorView是一個(gè)FrameLayout坯钦,我們Activity布局文件就是添加到了這個(gè)DecorView中。

看不懂是吧侈玄?沒(méi)事婉刀,接著看

這個(gè)結(jié)構(gòu)就像是這樣的:

Activity就是那些窗戶框,負(fù)責(zé)管理Window序仙,例如開(kāi)窗突颊、關(guān)窗戶等等。

DecorView就是像是給每個(gè)窗戶上貼了一張白紙诱桂,作用是讓我們顯示真正的畫面

在窗戶上貼了一張白紙---DecorView.png

所謂的setContentView,就是把Activity布局inflate成一個(gè)View之后呈昔,把這個(gè)View添加到DecorView中挥等,就像是給上圖的白紙上貼了一個(gè)窗花(View)。

我們的Activity布局就是窗花堤尾。

在這張紙上(DecorView)貼窗花(Activity的布局文件).png

換句話說(shuō)肝劲,窗戶看起來(lái)長(zhǎng)什么樣子,是由窗戶上的窗花決定的郭宝。

因?yàn)榇皯舯旧硎峭该鞯?/p>

好好把這段屢屢辞槐,仔細(xì)看看,因?yàn)槲业乃骄湍苤v到這個(gè)程度了粘室。想再讓我講的通俗易懂點(diǎn)榄檬,你得再等兩年。

但我建議你現(xiàn)在還是靜下心來(lái)看衔统,萬(wàn)一兩年后我轉(zhuǎn)行了呢鹿榜?

我們接著看

在這個(gè)結(jié)構(gòu)中海雪,我們需要了解的是DecorView的結(jié)構(gòu)

老規(guī)矩,先上圖

DecorView的結(jié)構(gòu)

解釋一下這張圖什么意思

DecorView自身是一個(gè)FrameLayout
這個(gè)FrameLayout中有一個(gè)LinearLayout
我們知道LinearLayout不是水平就是垂直方向舱殿,這里它是垂直方向的奥裸。

這個(gè)垂直方向的LinearLayout分為上下兩部分,每個(gè)部分都有每個(gè)部分的作用

上面的部分是ActionBar

黃色的部分是ActionBar.png

下面的部分是FrameLayout沪袭,這個(gè)FrameLayout是有id的湾宙,這個(gè)id是content

我們?cè)贏ctivity中setContentView就是把Activity的布局文件添加到了這個(gè)id為content的FrameLayout中了。

因?yàn)閕d是content冈绊,所以我們的api名稱設(shè)計(jì)成了setContentView

好了侠鳄,來(lái)一張相對(duì)立體一點(diǎn)的圖給大家總結(jié)一下

整體結(jié)構(gòu).png

上一段你從來(lái)沒(méi)有見(jiàn)過(guò)的代碼

public class ViewTreeMainActivity extends AppCompatActivity {
    private static final String TAG = "ViewTreeMainActivity===";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //把布局文件inflate成一個(gè)View
        View rootView = View.inflate(this,R.layout.activity_view_tree_main,null);
        //獲取那個(gè)id為content的FrameLayout
        FrameLayout content = findViewById(android.R.id.content);
        //把布局文件添加到FrameLayout中
        content.addView(rootView);

    }
}

如果你學(xué)習(xí)態(tài)度足夠認(rèn)真,那么你應(yīng)該把這段代碼敲一下焚碌,你會(huì)驚奇的發(fā)現(xiàn)畦攘,我們的Activity依然能正常展示。

而事實(shí)上十电,setContentView做的也就是這么一件事知押。

別翻源碼了,源碼里不是這樣寫的鹃骂。

感興趣的可以自己去翻一下phoneWindow中setContentView的源碼台盯。

現(xiàn)在我們回過(guò)頭來(lái)看看文章開(kāi)頭提到的面試題以及我給出的答案

不給Activity的根視圖添加id,怎么獲取到這個(gè)View畏线?

  FrameLayout rootView = findViewById(android.R.id.content);
  RelativeLayout relativeLayout = (LinearLayout) rootView.getChildAt(0);

現(xiàn)在你知道答案為什么這么寫了吧静盅?

最后還有幾個(gè)問(wèn)題需要交代一下:

上面的圖中為了讓大家更加容易理解,我用了一種錯(cuò)誤的表達(dá)方式:Activity的布局寝殴,這個(gè)是故意說(shuō)的不嚴(yán)謹(jǐn)?shù)妮锏瑸榱朔乐褂腥颂Ц埽卮寺暶饕幌隆?/p>

ActionBar的是否顯示蚣常、Window的背景顏色都跟Activity的主題有關(guān)當(dāng)市咽,這點(diǎn)相信地球人都知道。

我的問(wèn)題是ActionBar不顯示的時(shí)候抵蚊,具體是怎么操作的施绎?難道是通過(guò)setVisiable(GONE)的方式隱藏的嗎?

我們可以通過(guò)代碼requestWindowFeature(Window.FEATURE_NO_TITLE)來(lái)動(dòng)態(tài)隱藏Activity的ActionBar贞绳,不過(guò)這里有一點(diǎn)需要注意谷醉,這行代碼需要寫在setContentView之前調(diào)用(這個(gè)我求你自己敲個(gè)demo試試吧)

我的問(wèn)題是,為什么一定要寫在setContentView之前調(diào)用冈闭?

等一下俱尼,再加一個(gè)問(wèn)題,了解這些有什么用呢萎攒?

欲知后事号显,且聽(tīng)下回分解臭猜。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市押蚤,隨后出現(xiàn)的幾起案子蔑歌,更是在濱河造成了極大的恐慌,老刑警劉巖揽碘,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件次屠,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡雳刺,警方通過(guò)查閱死者的電腦和手機(jī)劫灶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)掖桦,“玉大人本昏,你說(shuō)我怎么就攤上這事∏雇簦” “怎么了涌穆?”我有些...
    開(kāi)封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)雀久。 經(jīng)常有香客問(wèn)我宿稀,道長(zhǎng),這世上最難降的妖魔是什么赖捌? 我笑而不...
    開(kāi)封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任祝沸,我火速辦了婚禮,結(jié)果婚禮上越庇,老公的妹妹穿的比我還像新娘罩锐。我一直安慰自己,他們只是感情好卤唉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布涩惑。 她就那樣靜靜地躺著,像睡著了一般搬味。 火紅的嫁衣襯著肌膚如雪境氢。 梳的紋絲不亂的頭發(fā)上蟀拷,一...
    開(kāi)封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天碰纬,我揣著相機(jī)與錄音,去河邊找鬼问芬。 笑死悦析,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的此衅。 我是一名探鬼主播强戴,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼亭螟,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了骑歹?” 一聲冷哼從身側(cè)響起预烙,我...
    開(kāi)封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎道媚,沒(méi)想到半個(gè)月后扁掸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡最域,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年谴分,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镀脂。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牺蹄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出薄翅,到底是詐尸還是另有隱情沙兰,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布匿刮,位于F島的核電站僧凰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏熟丸。R本人自食惡果不足惜训措,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望光羞。 院中可真熱鬧绩鸣,春花似錦、人聲如沸纱兑。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)潜慎。三九已至捡多,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铐炫,已是汗流浹背垒手。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倒信,地道東北人科贬。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鳖悠,于是被迫代替她去往敵國(guó)和親榜掌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子优妙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355