Android随笔-include、merge、ViewStub
概述
Android為XML布局提供了多種類型的組件標簽供使用,其中include、merge、ViewStub不常用,這三個標簽用于布局優化,本文對這三個標簽進行初略講解。
include
include是包含的意思,顧名思義就是布局重用的意思,也就是一塊布局寫好了之后,可以在其他布局中重復使用。實際開發中,使用include標簽地方不少,包括標題欄、控制面板、進度條、統一的按鈕文字等等,凡是共用的布局都可以使用include,大大減少了程序員的工作量,提高了開發效率。
以標題欄為例闡述include的使用。
因為取消了系統默認的標題欄,所以預覽圖中標題部分是沒有的。
3. 自定義標題欄。
自定義標題欄中包含返回按鈕和標題。
4. include標題欄
使用include標簽,需要注意一下幾點。
- include標簽不能作為根布局元素
- include標簽內不可以再添加其他元素。
像上面的寫法雖然不會報錯,但是TextView卻無法展示出來。
- include只能用在ViewGroup內
- 若include添加了一些屬性,則會以添加后的為準,且include里面包含的元素也會以添加后的屬性為準。
此時頁面效果就會發生改變。
- 若include中有設置了id,include包含的視圖中也設置了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="這是標題"android:textColor="@color/white"android:textSize="28dp" /></RelativeLayout>此時通過rl_title尋找tv_title會出現空指針。
RelativeLayout titleBar = findViewById(R.id.rl_title);TextView title = titleBar.findViewById(R.id.tv_title);結果會出現空指針異常。
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標簽復用其他布局時,可以視為在布局中又寫了一遍,所以獲取復用布局里面的元素直接使用findViewById即可。
TextView title = findViewById(R.id.tv_title);無需借助復用布局的再一次findViewById。
merge
merge翻譯過來的意思是合并、融入、融合、兼并的意思,merge標簽也就是起這樣的作用,用于減少布局層級,防止頁面過渡繪制,減少繪制時間,提高性能。
不使用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="第一個普通測試文本"/><TextViewandroid:layout_marginTop="50dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24dp"android:textColor="@color/black"android:text="第二個普通測試文本"/></LinearLayout>結果布局中的樹如下:
一共有兩級組件。
使用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="第一個merge測試文本"/><TextViewandroid:layout_marginTop="50dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="24dp"android:textColor="@color/black"android:text="第二個merge測試文本"/></merge>組件樹如下:
結果發現使用了merge后,merge里面的組件和父容器里面的組件是同一層級,而沒有使用merge是兩級,所以merge主要功能是用來減少布局層級。
使用merge也需要注意幾點。
- merge是一個標簽而不是一個view,所以在merge上不需要設置任何屬性
像上面的寫法其實是沒有任何效果的,merge里面的組件是根據使用merge的父容器來的。
- merge必須是根節點元素
否則代碼編譯的時候會報錯。
} 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.
簡單來講,ViewStub默認是一個不可見,且寬高都為0的,只有在運行時才會加載(懶加載)的組件。
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默認顯示為GONE,寬高都為0,此時也不會繪制。需要顯示的時候,需要調用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);當inflatedId不為NO_ID,也就是設置了id的時候,此時ViewStub的inflatedId就成為了根元素的id,此時可以直接通過findViewById獲取ViewStub 里面的元素。
如果沒有設置inflatedId時,可以直接通過findViewById(R.id.lv_test)獲取ViewStub里面的ListView。也可以通過inflate()直接獲取ViewStub里面的ListView。
注意:
- 可以通過判斷ViewStub的可見性(Visibility)判斷是否已加載。
- 如果通過inflate(),則需要通過對inflate獲取對象進行判空來判斷是否加載。
- 如果設置了inflatedId,則需要通過inflatedId查找目標父容器。
總結
以上是生活随笔為你收集整理的Android随笔-include、merge、ViewStub的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: visual studio-wdk8.1
- 下一篇: 计算机 映射网络驱动器,映射网络驱动器