【问题标题】:Android ViewStub change layouts programmaticallyAndroid ViewStub 以编程方式更改布局
【发布时间】:2016-05-25 15:12:57
【问题描述】:

这是我的用例:

我想在运行时更改我的膨胀布局,比如首先我膨胀布局 a,然后过一段时间我想显示布局 B,然后是布局 C,等等。

我在某处读到,我应该使用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>

我现在的问题是,当我为第一个布局充气时,它工作正常,但下一次当我尝试为第二个布局充气时,我得到了存根为空。

ViewStub stub = (ViewStub) findViewById(R.id.layout_stub);
        stub.setLayoutResource(layoutId);
        View inflated = stub.inflate();

我的理解是 Viewstub 是一个正在加载布局的容器,如果是这样的话 为什么我在尝试加载第二个布局时没有得到 ViewStub? (所以这意味着当我膨胀第一个布局(A)时,放置 ViewStub 的布局被完全删除了?)

我正在寻找使用 Viewstub 或替代方案来实现我的用例的任何指针。

【问题讨论】:

    标签: android viewstub


    【解决方案1】:

    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 的父级吗?
    • @Rakesh L 它是您在viewstub 中展开的布局的基本视图,您将删除该布局中包含的所有视图,并将它们替换为下一个布局的层次结构。 .
    • 通过这种方法,我们不需要 ViewStub。只需添加视图和删除视图是这里的主要内容。不是吗?
    【解决方案2】:

    是的,我认为您可以轻松地将其替换为另一个 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

    【讨论】:

    • 我有一个单独的布局文件并使用: val view: View = inflater.inflate(R.layout.bottom_navigation_view, null) 进行膨胀,然后将其用作参数它不起作用,因为它是父母为空。 view 参数到底长什么样?能举个例子吗?
    • @AdeDyas 这里是例子gist.github.com/sbelloz/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    相关资源
    最近更新 更多