一、ViewStub概述
ViewStub是Android中一个比较好用的工具类,可以让我们在布局中预先设置一些不常用的View,当需要使用时才加载进来,可以优化布局加载时间和内存开销。使用ViewStub可以将布局层次扁平化,以提高布局性能。
ViewStub的优点:
- 方便:可以增加应用程序的负载效率。
- 简单:加入的布局很简单,在XML文件使用。
- 高效:由于布局的添加是动态的进行,内存占用量更小。
- 快速:提高布局加载速度。
二、ViewStub的使用
1.在布局文件中添加ViewStub
可以在布局文件中添加ViewStub标签,通过设置android:layout布局参数设置ViewStub的位置,code示例如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_container" android:layout_width="match_parent" android:layout_height="match_parent"> <!--其他View省略--> <ViewStub android:id="@+id/view_stub" android:layout="@layout/custom_layout" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>
2.在Java文件中进行ViewStub的替换
在Java代码中可以使用ViewStub的inflate()方法将StubView替换为真正的View,并添加到布局中。在这个例子中,被inflate的布局叫做custom_layout.xml
ViewStub viewStub = findViewById(R.id.view_stub); View inflatedView = viewStub.inflate();
3.使用ViewStub的setVisibility()
也可以使用setVisibility()方法,将ViewStub替换为相应的真正View。
ViewStub viewStub = findViewById(R.id.view_stub); viewStub.setVisibility(View.VISIBLE);
4.使用ViewStub的getInflatedId()
可以使用getInflatedId()方法获取被inflate的View的ID。
ViewStub viewStub = findViewById(R.id.view_stub); int layoutId = viewStub.getInflatedId();
三、ViewStub原理
ViewStub本质上是一个代理View,当ViewStub替换为真正的View之后,ViewStub就不再存在,成为了普通的View。
可以通过以下方式查看ViewStub的监听事件:
ViewStub viewStub = findViewById(R.id.view_stub); viewStub.setOnInflateListener(new ViewStub.OnInflateListener() { @Override public void onInflate(ViewStub stub, View inflated) { Log.d("ViewStubDemo", "inflate()"); } });
四、ViewStub的扩展
基于ViewStub的原理,可以通过扩展ViewStub做一些有意思的功能。
1.自定义ViewStub
可以扩展ViewStub实现自定义的StubView,提供创建的接口。
public class MyViewStub extends ViewStub { private View mInflated = null; private int mLayoutId; public interface OnInflateListener { void onInflated(MyViewStub stub, View inflated); } private OnInflateListener mListener; public MyViewStub(Context context, AttributeSet attrs) { super(context, attrs); } public void setLayoutResource(int layoutId) { mLayoutId = layoutId; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mInflated == null) { setVisibility(View.GONE); LayoutInflater inflater = LayoutInflater.from(getContext()); View view = inflater.inflate(mLayoutId, this, true); if (mListener != null) { mListener.onInflated(this, view); } mInflated = view; } else { setMeasuredDimension(mInflated.getMeasuredWidth(), mInflated.getMeasuredHeight()); } } public void setOnInflateListener(OnInflateListener listener) { mListener = listener; } }
自定义的ViewStub可以在布局文件中使用。
<com.example.myviewstub.MyViewStub android:id="@+id/my_view_stub" android:layout="@layout/custom_layout" android:layout_width="match_parent" android:layout_height="wrap_content" />
在Java文件中可以使用如下代码进行ViewStub的替换(和ViewStub使用类似):
MyViewStub myViewStub = findViewById(R.id.my_view_stub); myViewStub.setLayoutResource(R.layout.custom_layout); View inflatedView = myViewStub.inflate();
2.ViewStub的懒加载
可以扩展ViewStub实现懒加载的StubView,可以控制是否需要加载。
public class LazyViewStub extends ViewStub { private boolean mIsVisibleToUser; private boolean mHasLoadOnce = false; public LazyViewStub(Context context, AttributeSet attrs) { super(context, attrs); } public void setVisibleToUser(boolean isVisibleToUser) { mIsVisibleToUser = isVisibleToUser; if (isVisibleToUser && !mHasLoadOnce) { inflate(); mHasLoadOnce = true; } } }
使用懒加载的ViewStub时,需要在Java代码中控制是否需要加载。
LazyViewStub lazyViewStub = findViewById(R.id.lazy_view_stub); lazyViewStub.setLayoutResource(R.layout.custom_layout); lazyViewStub.setVisibleToUser(isVisibleToUser);
五、总结
ViewStub是Android中一个方便、简单、高效和快速的工具类,可以优化布局加载时间和内存开销。除此之外,还可以扩展ViewStub实现一些有意思的功能,例如自定义StubView和懒加载。