在Android中可以很容易使用<include />标签复用布局,可是当使用<include />标签引入了一些复杂控件时,有些控件在实际的使用过程中,很少会使用它,这样以来会降低页面加载的速度。针对这样的情况,可以使用Android 提供<ViewStub />标签进行优化。
<ViewStub />标签是一个轻量级的View,它不会占据任何空间,也不参与布局的计算与绘制,只是在控件树中做一个最简单的占位符,只有在确实需要使用<ViewStub />标签引用的布局时,才会去加载布局。把这种行为称之为延迟加载最贴切不过了。在第四章中,讲解ListView绑定EmptyView的时候我们曾经使用过ViewStub,也做过简单介绍。
在使用ViewStub时,通常需要给它设置以下三个属性:
1、android:id 与其他控件一样,ViewStub也有id属性,根据它可以查找到ViewStub
2、android:layout 指向ViewStub引用的布局,与include标签的laytout属性类似
3、android:inflateId通过它能覆盖引用的布局文件根节点的id,与include标签的id属性类似。
下面的xml代码显示了ViewStub的使用方法:
在需要加载ViewStub引用的布局时,只需要调用它的inflate()方法即可,也可以通过改变它的visibility属性让ViewStub自动加载布局文件。
使用ViewStub的inflate()方法加载布局文件时,能够返回布局的根节点,如果需要操作布局的根节点,最好使用inflate()方法加载布局文件。
Java代码如下:
以下是本章Demo中ViewStub的使用方式:
下面通过本章的Demo对ViewStub进行练习,Demo中是一个简单的搜索界面,当点击搜索按钮后,布局中下方的ViewStub就会显示并显示进度条的提示,不进行搜索或者搜索完毕则不显示ViewStub。
JAVA代码如下:
其中涉及ViewStub的用法,我们已经讲解过了。同时需要注意Handler和Runnable,以及消息队列的使用,这些内容我们会在之后的章节中讲到。
Demo运行效果如下:
最后,在使用ViewStub时,需要注意一点,当ViewStub加载了它引用的布局之后,就会从控件树中移除,所以在编写代码时,不要使用生命周期很长的变量来引用ViewStub控件。
Demo源代码下载:
<ViewStub />标签是一个轻量级的View,它不会占据任何空间,也不参与布局的计算与绘制,只是在控件树中做一个最简单的占位符,只有在确实需要使用<ViewStub />标签引用的布局时,才会去加载布局。把这种行为称之为延迟加载最贴切不过了。在第四章中,讲解ListView绑定EmptyView的时候我们曾经使用过ViewStub,也做过简单介绍。
在使用ViewStub时,通常需要给它设置以下三个属性:
1、android:id 与其他控件一样,ViewStub也有id属性,根据它可以查找到ViewStub
2、android:layout 指向ViewStub引用的布局,与include标签的laytout属性类似
3、android:inflateId通过它能覆盖引用的布局文件根节点的id,与include标签的id属性类似。
下面的xml代码显示了ViewStub的使用方法:
1 | < ViewStub |
2 | android:id = "@+id/viewstub_progress" |
3 | android:inflatedId = "@+id/layout_progress_inflated" |
4 | android:layout = "@layout/layout_progressbar" |
5 | android:layout_width = "fill_parent" |
6 | android:layout_height = "wrap_content" |
7 | android:layout_gravity = "bottom" |
8 | /> |
在需要加载ViewStub引用的布局时,只需要调用它的inflate()方法即可,也可以通过改变它的visibility属性让ViewStub自动加载布局文件。
使用ViewStub的inflate()方法加载布局文件时,能够返回布局的根节点,如果需要操作布局的根节点,最好使用inflate()方法加载布局文件。
Java代码如下:
1 | ((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE); |
2 | // 或者 |
3 | View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate(); |
以下是本章Demo中ViewStub的使用方式:
1 | progressView = ((ViewStub)findViewById(R.id.viewstub_progress)).inflate(); |
2 |
3 | progressView.setVisibility(View.VISIBLE); |
4 | progressView.setVisibility(View.GONE); |
下面通过本章的Demo对ViewStub进行练习,Demo中是一个简单的搜索界面,当点击搜索按钮后,布局中下方的ViewStub就会显示并显示进度条的提示,不进行搜索或者搜索完毕则不显示ViewStub。
JAVA代码如下:
001 | package com.devdiv.test.layout_test; |
002 |
003 | import android.app.Activity; |
004 | import android.os.Bundle; |
005 | import android.os.Handler; |
006 | import android.view.View; |
007 | import android.view.View.OnClickListener; |
008 | import android.view.ViewStub; |
009 | import android.view.animation.Animation; |
010 | import android.view.animation.AnimationUtils; |
011 | import android.widget.Button; |
012 | import android.widget.ProgressBar; |
013 |
014 |
015 | public class ViewStub_ExampleActivity extends Activity { |
016 | private Button searchButton; |
017 | private Button cancelButton; |
018 | private View progressView; |
019 | private ProgressBar mProgressBar; |
020 | private static int count = 0 ; |
021 | |
022 | private Handler mHandler = new Handler(); |
023 | private Runnable mRunnable = new Runnable() { |
024 | |
025 | @Override |
026 | public void run() { |
027 | // TODO Auto-generated method stub |
028 | if (count > 10 ) { |
029 | searchCancel(); |
030 | } else { |
031 | mProgressBar.setProgress( 10 * count++); |
032 | mHandler.postDelayed(mRunnable, 500 ); |
033 | } |
034 | |
035 | } |
036 | }; |
037 | |
038 | @Override |
039 | protected void onCreate(Bundle savedInstanceState) { |
040 | // TODO Auto-generated method stub |
041 | super .onCreate(savedInstanceState); |
042 | setContentView(R.layout.layout_viewstub); |
043 | |
044 | searchButton = (Button) findViewById(R.id.button_search); |
045 | searchButton.setOnClickListener( new OnClickListener() { |
046 | |
047 | @Override |
048 | public void onClick(View v) { |
049 | // TODO Auto-generated method stub |
050 | searchStart(); |
051 | } |
052 | }); |
053 | } |
054 | |
055 | private void searchStart() { |
056 | if (progressView == null ) { |
057 | //这句话要注意!! |
058 | //加载布局!! |
059 | progressView = ((ViewStub)findViewById(R.id.viewstub_progress)).inflate(); |
060 | mProgressBar = (ProgressBar) progressView.findViewById(R.id.progressbar); |
061 | cancelButton = (Button) progressView.findViewById(R.id.button_cancel); |
062 | |
063 | cancelButton.setOnClickListener( new OnClickListener() { |
064 | |
065 | @Override |
066 | public void onClick(View v) { |
067 | // TODO Auto-generated method stub |
068 | searchCancel(); |
069 | } |
070 | }); |
071 | |
072 | } |
073 | |
074 | showViewStub(); |
075 | mHandler.post(mRunnable); |
076 | } |
077 | |
078 | private void searchCancel() { |
079 | if (progressView == null ) { |
080 | progressView = findViewById(R.id.viewstub_progress); |
081 | } |
082 | mHandler.removeCallbacks(mRunnable); |
083 | hideViewStub(); |
084 | } |
085 | |
086 | private void showViewStub() { |
087 | count = 0 ; |
088 | mProgressBar.setProgress( 0 ); |
089 | mProgressBar.setIndeterminate( false ); |
090 | progressView.startAnimation(AnimationUtils.loadAnimation( this , R.anim.slide_in )); |
091 | progressView.setVisibility(View.VISIBLE); |
092 | } |
093 | |
094 | private void hideViewStub() { |
095 | Animation anim = AnimationUtils.loadAnimation( this , R.anim.slide_out); |
096 | progressView.startAnimation(anim); |
097 | progressView.setVisibility(View.GONE); |
098 | |
099 | mProgressBar.setProgress( 0 ); |
100 | mProgressBar.setIndeterminate( true ); |
101 | |
102 | } |
103 |
104 | } |
其中涉及ViewStub的用法,我们已经讲解过了。同时需要注意Handler和Runnable,以及消息队列的使用,这些内容我们会在之后的章节中讲到。
Demo运行效果如下:
图8-20 ViewStub实例运行效果图1
图8-21 ViewStub实例运行效果图2
最后,在使用ViewStub时,需要注意一点,当ViewStub加载了它引用的布局之后,就会从控件树中移除,所以在编写代码时,不要使用生命周期很长的变量来引用ViewStub控件。
Demo源代码下载: