ViewStub使用详解——从源码看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用若引用保存起来。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
viewStub是一个轻量级的View,它可以延迟加载布局资源,而不必在Activity或Fragment的onCreate方法立即加载视图树,这样可以提高应用程序的性能。而viewBinding是一种新的方式,它允许您直接从布局文件获取对视图的引用,而不必使用findViewById()方法。当您使用viewStub时,您需要在布局文件定义一个viewStub元素,然后在代码使用它来加载布局资源。而当您使用viewBinding时,您需要在Activity或Fragment的onCreate方法初始化绑定对象,然后使用它来获取对布局文件的视图的引用。如果您要在使用viewBinding的情况下使用viewStub,您可以使用ViewBinding.inflate()方法来创建ViewBinding对象,然后使用ViewBinding.getRoot()方法来获取根视图,然后将其传递给viewStub的setVisibility()方法来显示或隐藏它。例如,您可以使用以下代码来显示viewStub: ``` private lateinit var binding: ActivityMainBinding private lateinit var stub: ViewStub override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) stub = binding.viewStub val inflatedView = binding.viewStub.inflate() // Do something with inflatedView } ``` 在这个例子,我们首先使用ViewBinding.inflate()方法初始化了绑定对象,然后使用ViewBinding.getRoot()方法获取根视图,并将其传递给viewStub的setVisibility()方法来显示它。然后,我们使用viewStub的inflate()方法来加载布局资源,并将返回的视图对象保存在一个变量,以便我们可以在代码使用它。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值