Android中的View(控件)樹結構

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

沒聽明白這個問題不要緊,我再給大家解釋一下

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

    }
}

注意看TODO中需要我們實現的邏輯,就是面試官的問題。

如果你看懂問題了,並且有答案了,那麼你可以點贊離開了。

如果你沒看懂問題,但是有答案了,我信了你的邪。

如果你沒看懂問題,並且沒有答案,麻煩你再審閱一下這個問題。

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

現在我揭曉答案,就兩行代碼

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

如果你碰到的面試官特別水,你現在可以抄抄作業,離開了。

悲哀的是,一般面試官會再來一句,爲什麼?

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

想知道這個所以然,我們就得從Android中的View(控件)樹結構說起

先上圖

 

 

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

簡單解釋一下:

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

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

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

這個結構就像是這樣的:

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

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

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

 

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

我們的Activity佈局就是窗花。

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

 

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

因爲窗戶本身是透明的

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

但我建議你現在還是靜下心來看,萬一兩年後我轉行了呢?

我們接着看

在這個結構中,我們需要了解的是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

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

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

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之前調用?

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

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

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章