码迷,mamicode.com
首页 > 其他好文 > 详细

ViewStub使用详解——从源码看ViewStub的使用

时间:2015-04-01 17:50:53      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:android   viewstub   

ViewStub就是一个轻量级的View,它在布局文件中以<ViewStub>标签的形式存在,在acitivity加载布局的时候并不会实例化这个View,而是当在代码中调用ViewStub的inflate()方法的时候才会实例化这个View。
定义一个ViewStub
ViewStub是一个轻量级的View,它没有大小,也不会执行任何的绘制。所以inflate它和把它放在view树中是非常划算的。每一个ViewStub都需要制定android:layout属性来制定它要inflate的布局文件。
例如:
<ViewStub
   
android:id="@+id/stub_import"
   
android:inflatedId="@+id/panel_import"
   
android:layout="@layout/progress_overlay"
   
android:layout_width="fill_parent"
   
android:layout_height="wrap_content"
   
android:layout_gravity="bottom" />
加载ViewStub的布局:
当你想加载ViewStub的布局时,可以通过调用setVisibility(View.VISIBLE)或者调用inflate()方法。
代码如下:
((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();
注意:inflate()方法返回了inflated的view。所以你不用再使用findViewById()方法。
当设置了可见性或者inflated之后,ViewStub元素就不再存在于view树中了。它被inflated的布局所替代了,而且inflated的根布局的id属性就是ViewStub所指定的android:inflatedId属性值。
这里值得注意的是:
在调用ViewStub的setVisibility()方法改变它的可见性的时候也会inflated这个ViewStub所指定的布局文件。但是如果在调用了一次这个方法之后再调用这个方法就不会去inflate了。我们看一下ViewStub中setVisibility()方法的源码:
@Override
    public void setVisibility(int visibility) {
        if (mInflatedViewRef != null) {
            View view = mInflatedViewRef.get();
            if (view != null) {
                view.setVisibility(visibility);
            } else {
                throw new IllegalStateException("setVisibility called on un-referenced view");
            }
        } else {
            super.setVisibility(visibility);
            if (visibility == VISIBLE || visibility == INVISIBLE) {
                inflate();
            }
        }
    }劵
其中mInflatedViewRef是一个若引用,它是inflated出来的view的一个若引用,上面的代码逻辑可以看出,当我们第一次调用setVisibility()方法时,它先判断需要inflate的view的引用是否为空,如果不为空,就拿到这个view并且设置它的可见性,如果需要inflate的view为空的话,不管调用的setVisibility()方法中传入的是可见还是不可见,它都会执行inflate()方法。

再来看看inflate()这个方法的源码:
public View inflate() {
        final ViewParent viewParent = getParent();

        if (viewParent != null && viewParent instanceof ViewGroup) {
            if (mLayoutResource != 0) {
                final ViewGroup parent = (ViewGroup) viewParent;
                final LayoutInflater factory = LayoutInflater.from(mContext);
                final View view = factory.inflate(mLayoutResource, parent,
                        false);

                if (mInflatedId != NO_ID) {
                    view.setId(mInflatedId);
                }

                final int index = parent.indexOfChild(this);
                parent.removeViewInLayout(this);

                final ViewGroup.LayoutParams layoutParams = getLayoutParams();
                if (layoutParams != null) {
                    parent.addView(view, index, layoutParams);
                } else {
                    parent.addView(view, index);
                }

                mInflatedViewRef = new WeakReference<View>(view);

                if (mInflateListener != null) {
                    mInflateListener.onInflate(this, view);
                }

                return view;
            } else {
                throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
            }
        } else {
            throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
        }
    }
这里我们可以看到,这个方法中做了如下几件事:
1. 获得当前viewStub的父控件,一般是一个ViewGroup对象。如果viewStub不是在一个ViewGroup中的话,会报出异常。
2. 然后使用LayoutInflater的inflate方法来加载布局文件,获得viewStub指定的布局所对应的view。
3. parent.removeViewInLayout(this);删除当前viewStub
4. 获得当前viewStub的布局参数,并把inflate出的view添加到parent中。
5. 将inflate出的view用若引用保存起来。

ViewStub使用详解——从源码看ViewStub的使用

标签:android   viewstub   

原文地址:http://blog.csdn.net/kent_todo/article/details/44808135

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!