Android ViewStub的使用


     ViewStub是一个不可见的,大小为0的View,最佳的用途就是实现View的延迟加载,在需要的时候再加载View。当调用ViewStub的setVisibility方法设置为可见或者调用inflate()方法初始化该View的时候,ViewStub引用的资源开始初始化,然后引用的资源会替代掉ViewStub,把自己填充在ViewStub的原位置。在需要的时候加载View,这样保证了资源的充分利用,并且由于引用的资源会替代掉ViewStub,导致重新加载时会报出异常,后边详细讲解。

        首先来说说ViewStub的一些特点:

         1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。

         2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。

         基于以上的特点,那么可以考虑使用ViewStub的情况有:

         1. 在程序的运行期间,某个布局需要加载时,在Inflate后,就不会有变化,除非重新启动。

         因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。

         2. 想要控制显示与隐藏的是一个布局文件,而非某个View。

         因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。 

         所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。这个地方需要区分开来!

下面上一个简单的例子:

main.xml:

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.hacktwo_prefernece.MainActivity" >

    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ViewStub测试"
        android:background="@android:color/background_light"
        android:textColor="@android:color/holo_green_light"
         />
    <Button 
        android:id="@+id/bt_get"
        android:layout_below="@id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="加载"
        android:textSize="20dp"
        android:gravity="center"
        />
    <Button 
        android:id="@+id/bt_down"
        android:layout_below="@id/bt_get"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="移除"
        android:textSize="20dp"
        android:gravity="center"
        />
    <ViewStub 
        android:id="@+id/view_content"
        android:layout_width="match_parent"
        android:layout_height="200dip"
        android:layout="@layout/tv_content"
        android:inflatedId="@+id/view_get"
         android:layout_below="@id/bt_down"
        />
    

</RelativeLayout>
需要加载的布局是tv_content.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:text="我是内容!"
    android:textSize="50sp">
    

</TextView>
MainActivity.java:

public class MainActivity extends Activity implements OnClickListener {

	private ViewStub mViewStub;
	private Button btGet;
	private Button btDown;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mViewStub = (ViewStub) findViewById(R.id.view_content);
		btGet = (Button) findViewById(R.id.bt_get);
		btGet.setOnClickListener(this);
		btDown = (Button) findViewById(R.id.bt_down);
		btDown.setOnClickListener(this);
	}


	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch(v.getId()){
		case R.id.bt_get:
			mViewStub.setVisibility(View.VISIBLE);
			break;
		case R.id.bt_down:
			mViewStub.setVisibility(View.INVISIBLE);
			break;
		}
	}
}
这个例子的实质是使用两个Button来控制这个ViewStub是否显示,效果如下:

初始状态:


在点击加载按钮后的状态:

点击移除按钮时,回到初始状态。下面对其做一下改动,主要是加载按钮处:

case R.id.bt_get:
			View viewGet = mViewStub.inflate();
			viewGet.setVisibility(View.VISIBLE);
			viewGet.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
					Toast.makeText(MainActivity.this, "Click", Toast.LENGTH_SHORT).show();
				}
			});
			break;

这段代码的含义是通过ViewStub加载目标布局,然后显示出来,点击的时候出现一个Toast提示,效果如下:


之后我有个误操作,再次点击加载按钮,发现程序挂掉了,Log提示:java.lang.IllegalStateException: ViewStub must have a non-null ViewGroup viewParent,解释如下:

        当调用inflate()方法的时候,ViewStub被引用的资源替代,并且返回引用的View。这样程序可以直接得到引用的View而不用再次调用findViewById()方法来查找了。只能在一个ViewStub对象上调用一次inflate()方法,因为当调用inflate()方法后原来的ViewStub对象已经被引用的资源所代替,ViewStub会从父组件中删除,引起上述异常。

       当你获取这个view的实例过后,就可以对其操作了,但是ViewStub将不会再起作用。切记这一点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值