我是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ō)起
先上圖
我們不熟悉的是紅虛線上的結(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è)窗戶上貼了一張白紙诱桂,作用是讓我們顯示真正的畫面
所謂的setContentView,就是把Activity布局inflate成一個(gè)View之后呈昔,把這個(gè)View添加到DecorView中挥等,就像是給上圖的白紙上貼了一個(gè)窗花(View)。
我們的Activity布局就是窗花堤尾。
換句話說(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自身是一個(gè)FrameLayout
這個(gè)FrameLayout中有一個(gè)LinearLayout
我們知道LinearLayout不是水平就是垂直方向舱殿,這里它是垂直方向的奥裸。
這個(gè)垂直方向的LinearLayout分為上下兩部分,每個(gè)部分都有每個(gè)部分的作用
上面的部分是ActionBar
下面的部分是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é)一下
上一段你從來(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)下回分解臭猜。