Android中的View(控件)樹結構

我是IT王魔王 這是個人第2篇IT原創android

嘗試寫出適合中級Android開發者的最好博客面試

有個小夥伴面試時碰到了一個問題:不給Activity的根視圖添加id,怎麼獲取到這個View?api

沒聽明白這個問題沒關係,我再給你們解釋一下bash

Activity的佈局文件以下ide

<?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 獲取佈局中的根節點 ,即本demo 佈局文件中的RelativeLayout
            }
        });

    }
}
複製代碼

注意看TODO中須要咱們實現的邏輯,就是面試官的問題。學習

若是你看懂問題了,而且有答案了,那麼你能夠點贊離開了。ui

若是你沒看懂問題,可是有答案了,我信了你的邪。this

若是你沒看懂問題,而且沒有答案,麻煩你再審閱一下這個問題。spa

若是你看懂問題了,可是沒有答案,那麼你應該繼續往下看

如今我揭曉答案,就兩行代碼

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

若是你碰到的面試官特別水,你如今能夠抄抄做業,離開了。

記得點贊

悲哀的是,通常面試官會再來一句,爲何?

是啊,爲何id要寫android.R.id.content?FrameLayout從哪裏來的?

想知道這個因此然,咱們就得從Android中的View(控件)樹結構提及

先上圖

Android中的控件樹結構.png

咱們不熟悉的是紅虛線上的結構,這部分也是咱們學習的重點。

簡單解釋一下:

一、每一個Activity中都有一個Window,Window用於顯示咱們的界面,Activity負責管理Window。 二、每一個Window都有一個根View--->DecorView。Window自身並不能顯示界面,Android中真正顯示畫面得靠View。

三、DecorView是一個FrameLayout,咱們Activity佈局文件就是添加到了這個DecorView中。

看不懂是吧?沒事,接着看

這個結構就像是這樣的:

Activity就是那些窗戶框,負責管理Window,例如開窗、關窗戶等等。

DecorView就是像是給每一個窗戶上貼了一張白紙,做用是讓咱們顯示真正的畫面

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

所謂的setContentView,就是把Activity佈局inflate成一個View以後,把這個View添加到DecorView中,就像是給上圖的白紙上貼了一個窗花(View)。

咱們的Activity佈局就是窗花。

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

換句話說,窗戶看起來長什麼樣子,是由窗戶上的窗花決定的。

由於窗戶自己是透明的

好好把這段屢屢,仔細看看,由於個人水平就能講到這個程度了。想再讓我講的通俗易懂點,你得再等兩年。

但我建議你如今仍是靜下心來看,萬一兩年後我轉行了呢?

咱們接着看

在這個結構中,咱們須要瞭解的是DecorView的結構

老規矩,先上圖

DecorView的結構

解釋一下這張圖什麼意思

DecorView自身是一個FrameLayout 這個FrameLayout中有一個LinearLayout 咱們知道LinearLayout不是水平就是垂直方向,這裏它是垂直方向的。

這個垂直方向的LinearLayout分爲上下兩部分,每一個部分都有每一個部分的做用

上面的部分是ActionBar

黃色的部分是ActionBar.png

下面的部分是FrameLayout,這個FrameLayout是有id的,這個id是content

咱們在Activity中setContentView就是把Activity的佈局文件添加到了這個id爲content的FrameLayout中了。

由於id是content,因此咱們的api名稱設計成了setContentView

好了,來一張相對立體一點的圖給你們總結一下

總體結構.png

上一段你歷來沒有見過的代碼

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

    }
}
複製代碼

若是你學習態度足夠認真,那麼你應該把這段代碼敲一下,你會驚奇的發現,咱們的Activity依然能正常展現。

而事實上,setContentView作的也就是這麼一件事。

別翻源碼了,源碼裏不是這樣寫的。

感興趣的能夠本身去翻一下phoneWindow中setContentView的源碼。

如今咱們回過頭來看看文章開頭提到的面試題以及我給出的答案

不給Activity的根視圖添加id,怎麼獲取到這個View?

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

如今你知道答案爲何這麼寫了吧?

最後還有幾個問題須要交代一下:

上面的圖中爲了讓你們更加容易理解,我用了一種錯誤的表達方式:Activity的佈局,這個是故意說的不嚴謹的,爲了防止有人擡槓,特此聲明一下。

ActionBar的是否顯示、Window的背景顏色都跟Activity的主題有關當,這點相信地球人都知道。

個人問題是ActionBar不顯示的時候,具體是怎麼操做的?難道是經過setVisiable(GONE)的方式隱藏的嗎?

咱們能夠經過代碼requestWindowFeature(Window.FEATURE_NO_TITLE)來動態隱藏Activity的ActionBar,不過這裏有一點須要注意,這行代碼須要寫在setContentView以前調用(這個我求你本身敲個demo試試吧)

個人問題是,爲何必定要寫在setContentView以前調用?

另外,這個結構其實並非足夠的細緻,都是爲了下降理解學習的難度(其實再細了我也不會) 等你掌握了這些內容後,之後看到別人寫的更加詳細的,接受起來纔會更加容易

等一下,再加一個問題,瞭解這些有什麼用呢?

欲知後事,且聽下回分解。

相關文章
相關標籤/搜索