我們?cè)谌粘i_(kāi)發(fā)中,我們可能會(huì)遇到有很多相似的布局,如果每一個(gè)XML文件都寫(xiě)一次,不說(shuō)麻煩,代碼也顯得冗余,而且可讀性也很差.這時(shí)候就需要include 了,本編文章將會(huì)介紹include贮泞、merge和ViewStub標(biāo)簽的用法供大家學(xué)習(xí)和參考楞慈。
include標(biāo)簽
include標(biāo)簽常用于將布局中的公共部分提取出來(lái)供其他layout共用,以實(shí)現(xiàn)布局模塊化,也是平常我們?cè)O(shè)計(jì)布局時(shí)用的最多的
include 官方文檔
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/textview"
android:textSize="24sp"/> <EditText
android:id="@+id/editText"
android:hint="@string/divide"
android:layout_width="300dp"
android:layout_height="wrap_content"/> </LinearLayout>
<?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="wrap_content"
android:gravity="center_horizontal"
> <TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="TextView_Relative"
android:textSize="24sp"/> <EditText
android:id="@+id/editText"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_below="@+id/textView"
android:hint="@string/divide"/> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/tb_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#00f"
app:theme="@style/AppTheme"
app:title="這是一個(gè)ToolBar"
app:titleTextColor="@android:color/white"/>
1.2啃擦、Activity的XML布局文件調(diào)用include標(biāo)簽:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--測(cè)試layout和<include>都設(shè)置ID的情況-->
<include
android:id="@+id/tb_toolbar"
layout="@layout/include_toolbar"/>
<!--如果只有單個(gè)include 這樣寫(xiě)就可以,加載的布局的子View,直接findViewByID就能找到-->
<include layout="@layout/include_text"/>
<!--如果有多個(gè)include,需要添加ID屬性--> <include
android:id="@+id/include_text1"
layout="@layout/include_text"/>
<!--這個(gè)layout用RelativeLayout 實(shí)現(xiàn)-->
<!--如果要使用layout_margin這樣的屬性,要同時(shí)加上layout_w/h屬性,不然沒(méi)反應(yīng)--> <include
android:id="@+id/include_text2"
layout="@layout/include_text_relative"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"/>
</LinearLayout>
1.3囊蓝、Activity中調(diào)用include標(biāo)簽layout中的子View:
private void initView() {
//如果include布局根容器和include標(biāo)簽中的id設(shè)置的是不同的值,這里獲取的mToolbar值將為null
Toolbar mToolbar = (Toolbar) findViewById(R.id.tb_toolbar); setSupportActionBar(mToolbar);
//普通include標(biāo)簽用法,直接拿子View屬性實(shí)現(xiàn)
TextView textView = (TextView) findViewById(R.id.textView); textView.setText("不加ID實(shí)現(xiàn)的include標(biāo)簽");
//多個(gè)include標(biāo)簽用法,添加ID,findViewByID找到layout,再找子控件
View view_include = findViewById(R.id.include_text1); TextView view_include_textView = (TextView) view_include.findViewById(R.id.textView); view_include_textView.setText("加了ID實(shí)現(xiàn)的include標(biāo)簽");
//多個(gè)include標(biāo)簽用法,添加ID,findViewByID找到layout,再找子控件
View view_include_Relative = findViewById(R.id.include_text2); TextView view_textView_relative = (TextView) view_include_Relative.findViewById(R.id.textView); view_textView_relative.setText("加了ID實(shí)現(xiàn)的include標(biāo)簽(RelaviteLayout)"); }
==include使用注意==
- 一個(gè)xml布局文件有多個(gè)include標(biāo)簽需要設(shè)置ID,才能找到相應(yīng)子View的控件,否則只能找到第一個(gè)include的layout布局,以及該布局的控件
- include標(biāo)簽如果使用layout_xx屬性,會(huì)覆蓋被include的xml文件根節(jié)點(diǎn)對(duì)應(yīng)的layout_xx屬性,建議在include標(biāo)簽調(diào)用的布局設(shè)置好寬高位置,防止不必要的bug
- include 添加id,會(huì)覆蓋被include的xml文件根節(jié)點(diǎn)ID,這里建議include和被include覆蓋的xml文件根節(jié)點(diǎn)設(shè)置同名的ID,不然有可能會(huì)報(bào)空指針異常
- 如果要在include標(biāo)簽下使用RelativeLayout,如layout_margin等其他屬性,記得要同時(shí)設(shè)置layout_width和layout_height,不然其它屬性會(huì)沒(méi)反應(yīng)
merge 標(biāo)簽
merge標(biāo)簽主要用于輔助include標(biāo)簽,在使用include后可能導(dǎo)致布局嵌套過(guò)多,多余的layout節(jié)點(diǎn)或?qū)е陆馕鲎兟?可通過(guò)hierarchy viewer工具查看布局的嵌套情況)
官方文檔說(shuō)明:merge用于消除視圖層次結(jié)構(gòu)中的冗余視圖,例如根布局是Linearlayout,那么我們又include一個(gè)LinerLayout布局就沒(méi)意義了,反而會(huì)減慢UI加載速度
merge 官方文檔
-
merge標(biāo)簽常用場(chǎng)景:
1.根布局是FrameLayout且不需要設(shè)置background或padding等屬性,可以用merge代替,因?yàn)锳ctivity的ContentView父元素就是FrameLayout,所以可以用merge消除只剩一個(gè)令蛉。
2.某布局作為子布局被其他布局include時(shí),使用merge當(dāng)作該布局的頂節(jié)點(diǎn),這樣在被引入時(shí)頂結(jié)點(diǎn)會(huì)自動(dòng)被忽略,而將其子節(jié)點(diǎn)全部合并到主布局中聚霜。
3.自定義View如果繼承LinearLayout(ViewGroup),建議讓自定義View的布局文件根布局設(shè)置成merge,這樣能少一層結(jié)點(diǎn)狡恬。
merge標(biāo)簽使用:
在XML布局文件的根布局如RelativeLayout直接改成merge即可
merge使用注意
1.因?yàn)閙erge標(biāo)簽并不是View,所以在通過(guò)LayoutInflate.inflate()方法渲染的時(shí)候,第二個(gè)參數(shù)必須指定一個(gè)父容器,且第三個(gè)參數(shù)必須為true,也就是必須為merge下的視圖指定一個(gè)父親節(jié)點(diǎn).
2.因?yàn)閙erge不是View,所以對(duì)merge標(biāo)簽設(shè)置的所有屬性都是無(wú)效的.
3.注意如果include的layout用了merge,調(diào)用include的根布局也使用了merge標(biāo)簽,那么就失去布局的屬性了
4.merge標(biāo)簽必須使用在根布局
5.ViewStub標(biāo)簽中的layout布局不能使用merge標(biāo)簽
ViewStub 標(biāo)簽
我們?cè)谧霭沧宽?xiàng)目的時(shí)候,經(jīng)常會(huì)有一個(gè)使用場(chǎng)景:需要在運(yùn)行時(shí)根據(jù)數(shù)據(jù)動(dòng)態(tài)決定顯示或隱藏某個(gè)View和布局蝎宇。
上述場(chǎng)景弟劲,我們通常的解決方案就是:就是把可能用到的View先寫(xiě)在布局里,再初始化其可見(jiàn)性都設(shè)為View.GONE姥芥,然后在代碼中根據(jù)數(shù)據(jù)動(dòng)態(tài)的更改它的可見(jiàn)性兔乞。
雖然這樣的實(shí)現(xiàn),邏輯簡(jiǎn)單而且控制起來(lái)比較靈活凉唐;但是也存在一定的缺點(diǎn)耗費(fèi)資源庸追。
ViewStub 標(biāo)簽最大的優(yōu)點(diǎn)是當(dāng)你需要時(shí)才會(huì)加載,使用它并不會(huì)影響UI初始化時(shí)的性能.各種不常用的布局像進(jìn)度條、顯示錯(cuò)誤消息等可以使用ViewStub標(biāo)簽,以減少內(nèi)存使用量,加快渲染速度.ViewStub是一個(gè)不可見(jiàn)的,實(shí)際上是把寬高設(shè)置為0的View.效果有點(diǎn)類(lèi)似普通的view.setVisible(),但性能體驗(yàn)提高不少
第一次初始化時(shí),初始化的是ViewStub View,當(dāng)我們調(diào)用inflate()或setVisibility()后會(huì)被remove掉,然后在將其中的layout加到當(dāng)前view hierarchy中台囱。
先來(lái)看看布局淡溯,一個(gè)是主布局,里面只定義二個(gè)ViewStub簿训,一個(gè)用來(lái)控制TextView一個(gè)用來(lái)控制ImageView咱娶,另外就是一個(gè)是為顯示文字的做的TextView布局,一個(gè)是為ImageView而做的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal">
<ViewStub
android:id="@+id/viewstub_demo_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout_marginTop="10dip"
android:layout="@layout/viewstub_demo_text_layout"/>
<ViewStub
android:id="@+id/viewstub_demo_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:layout="@layout/viewstub_demo_image_layout"/>
</LinearLayout>
為T(mén)extView的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/viewstub_demo_textview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#aa664411"
android:textSize="16sp"/>
</LinearLayout>
為ImageView的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/viewstub_demo_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
下面來(lái)看代碼煎楣,決定來(lái)顯示哪一個(gè),只需要找到相應(yīng)的ViewStub然后調(diào)用其infalte()就可以獲得相應(yīng)想要的布局:
public class ViewStubDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewstub_demo_activity);
if ((((int) (Math.random() * 100)) & 0x01) == 0) {
// to show text
// all you have to do is inflate the ViewStub for textview
ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text);
stub.inflate();
TextView text = (TextView) findViewById(R.id.viewstub_demo_textview);
text.setText("The tree of liberty must be refreshed from time to time" +
" with the blood of patroits and tyrants! Freedom is nothing but " +
"a chance to be better!");
} else {
// to show image
// all you have to do is inflate the ViewStub for imageview
ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image);
stub.inflate();
ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview);
image.setImageResource(R.drawable.happy_running_dog);
}
}
}
ViewStub標(biāo)簽使用注意
- ViewStub標(biāo)簽不支持merge標(biāo)簽
- ViewStub的inflate只能被調(diào)用一次,第二次調(diào)用會(huì)拋出異常,setVisibility可以被調(diào)用多次,但不建議這么做(ViewStub 調(diào)用過(guò)后,可能被GC掉,再調(diào)用setVisibility()會(huì)報(bào)異常)
- 為ViewStub賦值的android:layout_XX屬性會(huì)替換待加載布局文件的根節(jié)點(diǎn)對(duì)應(yīng)的屬性
擴(kuò)展:
Space組件
在ConstraintLayout出來(lái)前,我們寫(xiě)布局都會(huì)使用到大量的margin或padding,但是這種方式可讀性會(huì)很差,加一個(gè)布局嵌套又會(huì)損耗性能
鑒于這種情況,我們可以使用space,使用方式和View一樣,不過(guò)主要用來(lái)占位置,不會(huì)有任何顯示效果