1. ViewStub
在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。
那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。
推荐的做法是使用Android.view.ViewStub,ViewStub是一个轻量级的View,它一个看不见的(高和宽都是0),它本身不参与任何布局和绘制过程,占用资源非常小的控件。ViewStub的意义在于按需加载布局文件,在实际开发之中,有很多布局文件在正常情况下是不会显示的,比如网络异常的界面、各种不常用的布局进度条和显示错误信息等等这些布局文件是没有必要在整个界面初始化的时候将其加载进来的,通过ViewStub可以实现动态按需加载,减少内存使用量,加快渲染速度。
可以为ViewStub指定一个布局,在Inflate布局的时候,只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候或是调用了ViewStub.inflate()的时候,ViewStub所指向的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还是不要显示某个布局。
2. 下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制:
(1)首先来说说ViewStub的一些特点:
1)ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
2)ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。
(2)基于以上的特点,那么可以考虑使用ViewStub的情况有:
1)在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。
因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。
2)想要控制显示与隐藏的是一个布局文件,而非某个View。
因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。
3. ViewStub使用的示例:
(1)首先我们来到布局文件,如下:
一个是主布局,里面只定义二个ViewStub,一个用来控制TextView,一个用来控制ImageView;另外就是一个是为显示文字而做的TextView布局,一个是为显示图片而做的ImageView布局:
主布局文件activity_main.xml,如下:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 android:gravity="center_horizontal" 6 android:orientation="vertical" > 7 8 <ViewStub 9 android:id="@+id/viewstub_demo_text" 10 android:layout_width="wrap_content" 11 android:layout_height="wrap_content" 12 android:layout_marginLeft="5dip" 13 android:layout_marginRight="5dip" 14 android:layout_marginTop="10dip" 15 android:layout="@layout/viewstub_text_layout" /> 16 17 <ViewStub 18 android:id="@+id/viewstub_demo_image" 19 android:layout_width="wrap_content" 20 android:layout_height="wrap_content" 21 android:layout_marginLeft="5dip" 22 android:layout_marginRight="5dip" 23 android:layout="@layout/viewstub_image_layout" /> 24 25 </LinearLayout>
为TextView的布局文件viewstub_text_layout.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <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的布局文件viewstub_image_layout.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" 5 android:orientation="vertical" > 6 7 <ImageView 8 android:id="@+id/viewstub_demo_imageview" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" /> 11 12 </LinearLayout>
(2)来得MainActivity,如下:
1 package com.himi.viewstubdemo; 2 3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.ViewStub; 6 import android.widget.ImageView; 7 import android.widget.TextView; 8 9 public class MainActivity extends Activity { 10 11 public void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_main); 14 if ((((int) (Math.random() * 100)) & 0x01) == 0) { 15 // to show text 16 // all you have to do is inflate the ViewStub for textview 17 ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text); 18 stub.inflate(); 19 20 TextView text = (TextView) findViewById(R.id.viewstub_demo_textview); 21 text.setText(R.string.eyeOfgod); 22 } else { 23 // to show image 24 // all you have to do is inflate the ViewStub for imageview 25 ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image); 26 stub.inflate(); 27 28 ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview); 29 image.setImageResource(R.drawable.stars); 30 } 31 } 32 }
部署程序到手机上,结果如下: