Android ViewStub 以编程方式更改布局
Android ViewStub change layouts programmatically
这是我的用例:
我想在 运行 时更改我的充气布局,比如先充气布局 a,然后过一段时间我想显示布局 B,然后是布局 C 等
我在某处读到,与其在主布局中包含布局,然后 hiding/unhiding 我应该使用 viewstub 和 inflate。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/layout_stub"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
我现在的问题是,当我膨胀第一个布局时,它工作正常,但下次当我尝试膨胀第二个布局时,我得到了存根 null。
ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
stub.setLayoutResource(layoutId);
View inflated = stub.inflate();
我的理解是 Viewstub 是一个正在加载布局的容器,如果是的话
为什么我在尝试加载第二个布局时没有获得 ViewStub?
(所以这意味着当我膨胀第一个布局(A)时,放置 ViewStub 的布局被完全移除了?)
我正在寻找有关使用 Viewstub 或替代方案实现我的用例的任何指示。
A ViewStub 是一个占位符,一旦调用 ViewStub.inflate() 就会被膨胀的布局所取代。第二次调用 inflate 没有意义,因为 ViewStub 将不再位于层次结构中。相反,您应该获取对您的 LinearLayout 的引用,删除其视图,并将您的第二个布局添加为子布局。
ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
stub.setLayoutResource(layoutId);
stub.inflate(); // inflate 1st layout
ll.removeAllViews(); // remove previous view, add 2nd layout
ll.addView(LayoutInflater.from(context).inflate(secondLayoutId, ll, false));
是的,我认为您可以轻松地用另一个 ViewStub 替换它并以这种方式懒惰地扩充您的新布局:
为Java
public static ViewStub deflate(View view) {
ViewParent viewParent = view.getParent();
if (viewParent != null && viewParent instanceof ViewGroup) {
int index = ((ViewGroup) viewParent).indexOfChild(view);
int inflatedId = view.getId();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
((ViewGroup) viewParent).removeView(view);
Context context = ((ViewGroup) viewParent).getContext();
ViewStub viewStub = new ViewStub(context);
viewStub.setInflatedId(inflatedId);
viewStub.setLayoutParams(layoutParams);
((ViewGroup) viewParent).addView(viewStub, index);
return viewStub;
} else {
throw new IllegalStateException("Inflated View has not a parent");
}
}
或带扩展名的 Kotlin
fun ViewStub.deflate(view: View): ViewStub {
val viewParent = view.parent
if (viewParent != null && viewParent is ViewGroup) {
val index = viewParent.indexOfChild(view)
viewParent.removeView(view)
val viewStub = ViewStub(context).apply {
inflatedId = this@deflate.inflatedId
layoutParams = this@deflate.layoutParams
}
viewParent.addView(viewStub, index)
return viewStub
} else {
throw IllegalStateException("Inflated View has not a parent")
}
}
查看 gist
这是我的用例:
我想在 运行 时更改我的充气布局,比如先充气布局 a,然后过一段时间我想显示布局 B,然后是布局 C 等
我在某处读到,与其在主布局中包含布局,然后 hiding/unhiding 我应该使用 viewstub 和 inflate。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ViewStub
android:id="@+id/layout_stub"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
我现在的问题是,当我膨胀第一个布局时,它工作正常,但下次当我尝试膨胀第二个布局时,我得到了存根 null。
ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
stub.setLayoutResource(layoutId);
View inflated = stub.inflate();
我的理解是 Viewstub 是一个正在加载布局的容器,如果是的话 为什么我在尝试加载第二个布局时没有获得 ViewStub? (所以这意味着当我膨胀第一个布局(A)时,放置 ViewStub 的布局被完全移除了?)
我正在寻找有关使用 Viewstub 或替代方案实现我的用例的任何指示。
A ViewStub 是一个占位符,一旦调用 ViewStub.inflate() 就会被膨胀的布局所取代。第二次调用 inflate 没有意义,因为 ViewStub 将不再位于层次结构中。相反,您应该获取对您的 LinearLayout 的引用,删除其视图,并将您的第二个布局添加为子布局。
ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
stub.setLayoutResource(layoutId);
stub.inflate(); // inflate 1st layout
ll.removeAllViews(); // remove previous view, add 2nd layout
ll.addView(LayoutInflater.from(context).inflate(secondLayoutId, ll, false));
是的,我认为您可以轻松地用另一个 ViewStub 替换它并以这种方式懒惰地扩充您的新布局:
为Java
public static ViewStub deflate(View view) {
ViewParent viewParent = view.getParent();
if (viewParent != null && viewParent instanceof ViewGroup) {
int index = ((ViewGroup) viewParent).indexOfChild(view);
int inflatedId = view.getId();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
((ViewGroup) viewParent).removeView(view);
Context context = ((ViewGroup) viewParent).getContext();
ViewStub viewStub = new ViewStub(context);
viewStub.setInflatedId(inflatedId);
viewStub.setLayoutParams(layoutParams);
((ViewGroup) viewParent).addView(viewStub, index);
return viewStub;
} else {
throw new IllegalStateException("Inflated View has not a parent");
}
}
或带扩展名的 Kotlin
fun ViewStub.deflate(view: View): ViewStub {
val viewParent = view.parent
if (viewParent != null && viewParent is ViewGroup) {
val index = viewParent.indexOfChild(view)
viewParent.removeView(view)
val viewStub = ViewStub(context).apply {
inflatedId = this@deflate.inflatedId
layoutParams = this@deflate.layoutParams
}
viewParent.addView(viewStub, index)
return viewStub
} else {
throw IllegalStateException("Inflated View has not a parent")
}
}
查看 gist