android LayoutInflater、setContentView、findviewbyid 區分解析

許佳佳233發表於2016-05-31

一、LayoutInflater.inflate(layoutId, root, boolen)中三個引數的意義及作用

(這點可以參考鴻洋前輩部落格地址:http://blog.csdn.net/lmj623565791/article/details/38171465


主要知識點其實很少,如下:

若temp為layoutId所代表的佈局,inflate的三種方法區分如下:

View view=LayoutInflater.Inflate(layoutId, null )只建立temp ,temp.LayoutParams=null,返回temp
View view=LayoutInflater.Inflate(layoutId, root, false )建立temp,temp.LayoutParams=root.LayoutParams;返回temp
View view=LayoutInflater.Inflate(layoutId, root, true ) 建立temp,然後執行root.addView(temp, params);最後返回root


關於點三條可能難以理解,此處筆者自己寫了一個例子:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/main_layout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Main Text View"/>

</LinearLayout>
button_layout.xml

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

MainActivity.java

package com.example.double2.layoutinflatertest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private LinearLayout mainLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainLayout = (LinearLayout) findViewById(R.id.main_layout);
        LayoutInflater layoutInflater = LayoutInflater.from(this);

        View buttonLayout = layoutInflater.inflate(R.layout.button_layout, null);
        mainLayout.addView(buttonLayout);

//        View buttonLayout = layoutInflater.inflate(R.layout.button_layout, mainLayout,true);
    }
}


當執行如下兩句時,佈局如下:

        View buttonLayout = layoutInflater.inflate(R.layout.button_layout, null);
        mainLayout.addView(buttonLayout);


當執行如下一句時,佈局如下:

        View buttonLayout = layoutInflater.inflate(R.layout.button_layout, mainLayout,true);



二、又上圖可知,兩種方式都是可以給activity_main中加入button佈局了,但是讓人奇怪的是,為什麼兩者是同一個button,顯示的卻會有差別呢?第二個問題就自然出來了。


解決辦法:我們給button_layout中的button加上一個RelativeLayout,如下:

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

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"/>
</RelativeLayout>
然後我們可以發現,兩種方式都只會有一種效果了,如下:



可以發現,這往往就是我們最想要的效果,就是這個button本來多大,就給它。這樣我們修改這個button的時候才比較方便。

那麼是什麼導致在第一個問題中,button無法顯示原來的大小的呢?

        View buttonLayout = layoutInflater.inflate(R.layout.button_layout, null);
        mainLayout.addView(buttonLayout);

當我們執行如上程式碼時,root為null,我們獲得的buttonLayout的LayoutParams為null。當我們在viewgroup中使用addView(View child)方法,新增一個沒有LayoutParams屬性的子view。在viewgroup方法內部,它會呼叫generateDefaultLayoutParams()生成一個LayoutParams賦值個給子view。


LayoutParams有什麼用呢?

簡單來說,當一個view的LayoutParams存在時,該佈局的寬高設定才會有效。而一個view需要存在LayoutParams,就必須存在父佈局。

關於LayoutParams,可以參考這篇部落格:http://blog.csdn.net/double2hao/article/details/51438798

        View buttonLayout = layoutInflater.inflate(R.layout.button_layout, mainLayout,true);
而當我們執行這行程式碼的時候,我們最終返回的是root,而root即為activity_main中的LinearLayout。也就和button本身並沒有什麼關係了。



三、那麼activity_main中的LinearLayout也為空,為什麼我們經常使用setContentView(R.id.XXX)的時候卻不會造成LayoutParams的缺失而導致佈局無法準確顯示的問題呢?


如此,我們就需要去了解setContentView()和layoutInflater.inflate()的區別了。

setContentView()設定佈局的時候,Android會自動在佈局檔案的最外層再巢狀一個FrameLayout,所以設定的佈局是存在LayoutParams的,也因此可以正常顯示。


關於問題二和三,如果還有興趣的讀者,可以參考一下郭霖前輩的部落格:

http://blog.csdn.net/guolin_blog/article/details/12921889


四,findviewbyid()和LayoutInflater.Inflate()有什麼區別呢?

findViewById():從setContentView()已經設定的layout中獲取到某個控制元件。

Inflate():把某個layout從xml檔案中例項化成一個物件。

相關文章