Android随笔-include、merge、ViewStub
概述
Android為XML布局提供了多種類型的組件標(biāo)簽供使用,其中include、merge、ViewStub不常用,這三個(gè)標(biāo)簽用于布局優(yōu)化,本文對(duì)這三個(gè)標(biāo)簽進(jìn)行初略講解。
include
include是包含的意思,顧名思義就是布局重用的意思,也就是一塊布局寫好了之后,可以在其他布局中重復(fù)使用。實(shí)際開發(fā)中,使用include標(biāo)簽地方不少,包括標(biāo)題欄、控制面板、進(jìn)度條、統(tǒng)一的按鈕文字等等,凡是共用的布局都可以使用include,大大減少了程序員的工作量,提高了開發(fā)效率。
以標(biāo)題欄為例闡述include的使用。
因?yàn)槿∠讼到y(tǒng)默認(rèn)的標(biāo)題欄,所以預(yù)覽圖中標(biāo)題部分是沒有的。
3. 自定義標(biāo)題欄。
自定義標(biāo)題欄中包含返回按鈕和標(biāo)題。
4. include標(biāo)題欄
使用include標(biāo)簽,需要注意一下幾點(diǎn)。
- include標(biāo)簽不能作為根布局元素
- include標(biāo)簽內(nèi)不可以再添加其他元素。
像上面的寫法雖然不會(huì)報(bào)錯(cuò),但是TextView卻無法展示出來。
- include只能用在ViewGroup內(nèi)
- 若include添加了一些屬性,則會(huì)以添加后的為準(zhǔn),且include里面包含的元素也會(huì)以添加后的屬性為準(zhǔn)。
此時(shí)頁(yè)面效果就會(huì)發(fā)生改變。
- 若include中有設(shè)置了id,include包含的視圖中也設(shè)置了id,則不能通過include自己的id獲取include里面的組件
titlebar.xml中布局如下。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rl_title"android:layout_width="match_parent"android:layout_height="52dp"android:background="#00BCD4"><ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:src="@drawable/ic_baseline_keyboard_arrow_left_24" /><TextViewandroid:id="@+id/tv_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:text="這是標(biāo)題"android:textColor="@color/white"android:textSize="28dp" /></RelativeLayout>此時(shí)通過rl_title尋找tv_title會(huì)出現(xiàn)空指針。
RelativeLayout titleBar = findViewById(R.id.rl_title);TextView title = titleBar.findViewById(R.id.tv_title);結(jié)果會(huì)出現(xiàn)空指針異常。
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.widget.RelativeLayout.findViewById(int)' on a null object referenceat com.example.content.MainActivity.onCreate(MainActivity.java:22)include標(biāo)簽復(fù)用其他布局時(shí),可以視為在布局中又寫了一遍,所以獲取復(fù)用布局里面的元素直接使用findViewById即可。
TextView title = findViewById(R.id.tv_title);無需借助復(fù)用布局的再一次findViewById。
merge
merge翻譯過來的意思是合并、融入、融合、兼并的意思,merge標(biāo)簽也就是起這樣的作用,用于減少布局層級(jí),防止頁(yè)面過渡繪制,減少繪制時(shí)間,提高性能。
不使用merge
普通布局。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><include layout="@layout/titlebar"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="Hello World!"android:textColor="@color/black"android:textSize="48dp" /><include layout="@layout/normal_item"/></LinearLayout>其中normal_item沒有使用merge。
<?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"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24dp"android:textColor="@color/black"android:text="第一個(gè)普通測(cè)試文本"/><TextViewandroid:layout_marginTop="50dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24dp"android:textColor="@color/black"android:text="第二個(gè)普通測(cè)試文本"/></LinearLayout>結(jié)果布局中的樹如下:
一共有兩級(jí)組件。
使用merge
使用merge就是將上訴normal_item中LinearLayout改成merge。
<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24dp"android:textColor="@color/black"android:text="第一個(gè)merge測(cè)試文本"/><TextViewandroid:layout_marginTop="50dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24dp"android:textColor="@color/black"android:text="第二個(gè)merge測(cè)試文本"/></merge>組件樹如下:
結(jié)果發(fā)現(xiàn)使用了merge后,merge里面的組件和父容器里面的組件是同一層級(jí),而沒有使用merge是兩級(jí),所以merge主要功能是用來減少布局層級(jí)。
使用merge也需要注意幾點(diǎn)。
- merge是一個(gè)標(biāo)簽而不是一個(gè)view,所以在merge上不需要設(shè)置任何屬性
像上面的寫法其實(shí)是沒有任何效果的,merge里面的組件是根據(jù)使用merge的父容器來的。
- merge必須是根節(jié)點(diǎn)元素
否則代碼編譯的時(shí)候會(huì)報(bào)錯(cuò)。
} else if (TAG_MERGE.equals(name)) {throw new InflateException("<merge /> must be the root element");} else {- merge必須要有父容器
ViewStub
A ViewStub is an invisible, zero-sized View that can be used to lazily inflate layout resources at runtime. When a ViewStub is made visible, or when inflate() is invoked, the layout resource is inflated. The ViewStub then replaces itself in its parent with the inflated View or Views. Therefore, the ViewStub exists in the view hierarchy until setVisibility(int) or inflate() is invoked. The inflated View is added to the ViewStub’s parent with the ViewStub’s layout parameters. Similarly, you can define/override the inflate View’s id by using the ViewStub’s inflatedId property.
簡(jiǎn)單來講,ViewStub默認(rèn)是一個(gè)不可見,且寬高都為0的,只有在運(yùn)行時(shí)才會(huì)加載(懶加載)的組件。
public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context);final TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ViewStub, defStyleAttr, defStyleRes);saveAttributeDataForStyleable(context, R.styleable.ViewStub, attrs, a, defStyleAttr,defStyleRes);mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);a.recycle();setVisibility(GONE);setWillNotDraw(true);}...@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(0, 0);}ViewStub默認(rèn)顯示為GONE,寬高都為0,此時(shí)也不會(huì)繪制。需要顯示的時(shí)候,需要調(diào)用setVisibility()或者Inflate()才可以加載布局。
使用
<ViewStubandroid:id="@+id/vs_test"android:layout_width="200dp"android:layout_height="200dp"android:inflatedId="@+id/vs_inflate"android:layout="@layout/viewstub_item" />其中viewstub_item:
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/lv_test"android:layout_width="match_parent"android:layout_height="match_parent"> </ListView>通過inflatedId就可以獲取viewstub_item里面的ListView 。
ViewStub viewStub = findViewById(R.id.vs_test);// 加載viewStub.setVisibility(View.VISIBLE);// 通過inflatedId獲取viewstub_item里面的listViewListView listView = findViewById(R.id.vs_inflate);當(dāng)inflatedId不為NO_ID,也就是設(shè)置了id的時(shí)候,此時(shí)ViewStub的inflatedId就成為了根元素的id,此時(shí)可以直接通過findViewById獲取ViewStub 里面的元素。
如果沒有設(shè)置inflatedId時(shí),可以直接通過findViewById(R.id.lv_test)獲取ViewStub里面的ListView。也可以通過inflate()直接獲取ViewStub里面的ListView。
注意:
- 可以通過判斷ViewStub的可見性(Visibility)判斷是否已加載。
- 如果通過inflate(),則需要通過對(duì)inflate獲取對(duì)象進(jìn)行判空來判斷是否加載。
- 如果設(shè)置了inflatedId,則需要通過inflatedId查找目標(biāo)父容器。
總結(jié)
以上是生活随笔為你收集整理的Android随笔-include、merge、ViewStub的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: visual studio-wdk8.1
- 下一篇: Android四大组件之Service