如何在安卓中使用View Stub

76

我想在Android中使用ViewStub,请帮我。我已经创建了

ViewStub stub = new ViewStub;
View inflated = stub.inflate(); 
如何以编程的方式使用它?

3
这里Romain Guy更详细地解释了:http://android-developers.blogspot.de/2009/03/android-layout-tricks-3-optimize-with.html - Malachiasz
3个回答

130

就像文档所说的那样,ViewStub是一种惰性膨胀的View

你可以像这样在XML文件中声明一个ViewStub

 <ViewStub android:id="@+id/stub"
           android:inflatedId="@+id/subTree"
           android:layout="@layout/mySubTree"
           android:layout_width="120dip"
           android:layout_height="40dip" />

android:layout 属性是一个引用,引用的是在调用 inflate() 时将会被填充到旁边的 View。因此,

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

当调用inflate()方法时,ViewStub会从其父视图中移除,并用正确的View(即mySubTree布局的根视图)替换它。

如果您想以编程方式执行此操作,则代码应如下:

ViewStub stub = new ViewStub(this);
stub.setLayoutResource(R.layout.mySubTree);
stub.inflate(); 

2
ViewStub的android:layout_width="120dip"有什么意义,如果它是不可见的,并且在充气后被替换? - Malachiasz
我的猜测是,这是为了使布局的其余部分能够正确对齐。 - A. Steenbergen
6
如何在Android Studio预览中显示膨胀视图? - Denis Nek
我遇到了“指定的子项已经有一个父项。您必须先在子项的父项上调用removeView()”错误,有人能帮我吗? - Ahmad Vatani
@DenisNek Android问题跟踪器上有一个问题,但是还没有人回答。https://code.google.com/p/android/issues/detail?id=205335 - Arturo Mejia
通过使用ViewStub的inflatedId来定义/覆盖inflate View的id,这是否意味着它将使用具有inflated Id的根id重置视图的根id。 - Shubham AgaRwal

28

ViewStub的作用是为了提高布局渲染效率。使用ViewStub,可以手动创建视图但不会将其添加到视图层次结构中。在运行时,可以很容易地填充它,当ViewStub被填充时,ViewStub的内容将被定义布局所替换。

在activity_main.xml中,我们定义了ViewStub但尚未创建它。enter image description here

下面是一个简单的例子,可以更好地理解ViewStub:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/content"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="create the view stub" />
     <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hide the stub." />

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1" >

        <ViewStub
            android:id="@+id/stub_import"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:inflatedId="@+id/content_import"
            android:layout="@layout/splash" />
    </RelativeLayout>
</LinearLayout>

在运行时,当我们进行充气时,内容将被用视图存根中定义的布局替换。

public class MainActivity extends Activity {

    Button b1 = null;
    Button b2 = null;

    ViewStub stub = null;
    TextView tx = null;

    int counter = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        b1 = (Button) findViewById(R.id.btn1);
        b2 = (Button) findViewById(R.id.btn2);
        b1.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (stub == null) {     
                    stub = (ViewStub) findViewById(R.id.stub_import);
                    View inflated = stub.inflate();
                    tx = (TextView) inflated.findViewById(R.id.text1);
                    tx.setText("thanks a lot my friend..");
                } 

            }
        });

        b2.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                if (stub != null) {
                    stub.setVisibility(View.GONE);
                }

            }
        });

    }

enter image description here

让我们再次查看视图层次结构:

enter image description here

当我们填充ViewStub时,它将从视图层次结构中移除。


1
注意:inflate() 方法完成后会返回已填充的 View,因此如果您需要与布局交互,则无需调用 findViewById()。所以 stub = (ViewStub) findViewById(R.id.stub_import); tx = (TextView) findViewById(R.id.text1); tx.setText("非常感谢你,我的朋友.."); stub.inflate(); 参考:http://developer.android.com/training/improving-layouts/loading-ondemand.html - user1154390
考虑到它不支持在内容视图中进行合并,这个原因完全是愚蠢的。我认为这个理由是无效的。它不利于有效布局;相反,它会使它们变得更糟。 - wkhatch
@huseyin,对于 b2 按钮,您使用 View.GONE 来设置可见性。Android Developers Blog 使用 View.INVISIBLE。您能否说明为什么使用 GONE 而不是 INVISIBLE? - AJW

11

这里有一个示例,演示在运行时显示/隐藏和更改ViewStub数据的方法。

activity_main.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/buttonShow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show View Stub"/>

    <Button
        android:id="@+id/buttonHide"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hide View Stub"/>

    <ViewStub
        android:id="@+id/viewStub"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout="@layout/layout_of_view_stub"
        />

</LinearLayout>

layout_of_view_stub.xml

<TextView
    android:id="@+id/textInViewStub"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="ViewStub Button"
    />

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private ViewStub viewStub;
    private Button buttonShow;
    private Button buttonHide;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        buttonShow = findViewById(R.id.buttonShow);
        buttonHide = findViewById(R.id.buttonHide);
        buttonShow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showViewStub();
            }
        });

        buttonHide.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hideViewStub();
            }
        });
    }

    private void showViewStub() {
        if (viewStub == null) {
            viewStub = findViewById(R.id.viewStub);

            // If you want to change data of ViewStub at runtime, you can do like this
            View inflatedView = viewStub.inflate();
            TextView textViewInViewStub = inflatedView.findViewById(R.id.textInViewStub);
            textViewInViewStub.setText("ABC");
        }
        viewStub.setVisibility(View.VISIBLE);
    }

    private void hideViewStub() {
        if (viewStub == null) {
            return;
        }
        viewStub.setVisibility(View.GONE);
    }
}

easy to understand. Thank you - HungNM2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接