我们知道Android中的<include>标签,该标签可以在布局文件当中引用另外一个布局文件,这种方式是在布局文件中固定导入,使用起来不是很方便。
ViewStub的功能和<include>的功能类似,也是实现引用另外一个布局。但是唯一不同的是ViewStub并不会马上装载引用布局文件,只有在调用了ViewStub.inflate();或ViewStub.setVisibilty(VISIBLE),ViewStub 才会装载引用的控件。
ViewStub是一个轻量级的View,它是一个看不见的、不占布局位置、占用资源非常小的控件。我们在用的时候可以为ViewStub制定一个布局,在inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub设置为可见的时候或是调用了ViewStub.inflate()的时候,ViewStub所指向的布局就会被inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的控制要不要显示某个布局。
activity_main.xml
<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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:id="@+id/showBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="动态添加布局" />
<Button
android:id="@+id/deleteBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="动态隐藏布局" />
</LinearLayout>
<!-- 动态加载布局文件 -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ViewStub
android:id="@+id/viewstub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/next" />
</LinearLayout>
</LinearLayout>
next.xml
<?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" >
<RatingBar
android:id="@+id/ratingBar1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
MainActivity.java
package com.example.viewstub;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewStub;
import android.widget.Button;
public class MainActivity extends Activity {
private Button button1, button2;
private ViewStub viewStub;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.showBtn);
button2 = (Button) findViewById(R.id.deleteBtn);
viewStub = (ViewStub) findViewById(R.id.viewstub);
button1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// 表示填充动态布局
viewStub.inflate();
//viewStub.inflate();方法只能被调用一次,多次点击会出错
//或者viewStub.setVisibility(View.VISIBLE);可多次点击
}
});
button2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// 隐藏动态加载的布局
viewStub.setVisibility(View.GONE);
}
});
}
}
点击“动态添加布局”按钮就会出现下面的UI
点击“动态隐藏布局”按钮就会出现下面的UI
这样就可以了。另外,小编在写的时候还存在一些问题,需要大家注意一下。
1、多次调用inflate()错误
当你多次调用ViewStub.inflate()的时候,已经用ViewStub里面指定的layout代替了ViewStub。换句话说,ViewStub已经不再activity_main.xml里面了,而在inflate()源码里面。
final ViewParent viewParent = getParent();
if (viewParent!=null && viewParent instanceof ViewGroup)
这时候getParent()已经是null了,所以再一次点击会出错。
2、调用viewStub.setVisibility(View.VISIBLE);可多次点击
在源码中super.setVisibility(View.VISIBILE);
inflate();
先不显示,然后次啊调用inflate(),所以ViewStub可能还在activity_main.xml里面,所以getParent()不会报错。