精华内容
参与话题
问答
  • ViewStub基本用法

    千次阅读 2018-09-16 10:20:27
    在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改...

    在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改它的可见性。这样的做法的优点是逻辑简单而且控制起来比较灵活。但是它的缺点就是,耗费资源。虽然把View的初始可见View.GONE但是在Inflate布局的时候View仍然会被Inflate,也就是说仍然会创建对象,会被实例化,会被设置属性。也就是说,会耗费内存等资源。

     推荐的做法是使用android.view.ViewStub,ViewStub 是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有 ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向 的布局就会被Inflate和实例化,然后ViewStub的布局属性都会传给它所指向的布局。这样,就可以使用ViewStub来方便的在运行时,要还 是不要显示某个布局。

          但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。

         首先来说说ViewStub的一些特点:

             1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。

             2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。

         基于以上的特点,那么可以考虑使用ViewStub的情况有:

             1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。

                  因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。

             2. 想要控制显示与隐藏的是一个布局文件,而非某个View。

                  因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。

         所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。

    下面来看一个实例

    在这个例子中,要显示二种不同的布局,一个是用TextView显示一段文字,另一个则是用ImageView显示一个图片。这二个是在onCreate()时决定是显示哪一个,这里就是应用ViewStub的最佳地点。

    先来看看布局,一个是主布局,里面只定义二个ViewStub,一个用来控制TextView一个用来控制ImageView,另外就是一个是为显示文字的做的TextView布局,一个是为ImageView而做的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center_horizontal">
        <ViewStub
            android:id="@+id/viewstub_demo_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dip"
            android:layout_marginRight="5dip"
            android:layout_marginTop="10dip"
            android:layout="@layout/viewstub_demo_text_layout"/>
        <ViewStub
            android:id="@+id/viewstub_demo_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="5dip"
            android:layout_marginRight="5dip"
            android:layout="@layout/viewstub_demo_image_layout"/>
    </LinearLayout>

    为TextView的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/viewstub_demo_textview"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#aa664411"
            android:textSize="16sp"/>
    </LinearLayout>

    为ImageView的布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <ImageView
            android:id="@+id/viewstub_demo_imageview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    </LinearLayout>

    下面来看代码,决定来显示哪一个,只需要找到相应的ViewStub然后调用其infalte()就可以获得相应想要的布局:

    package com.itydl.myapplication;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.ViewStub;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            if ((((int) (Math.random() * 100)) & 0x01) == 0) {
                // to show text
                // all you have to do is inflate the ViewStub for textview
                ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_text);
                stub.inflate();
                TextView text = (TextView) findViewById(R.id.viewstub_demo_textview);
                text.setText("The tree of liberty must be refreshed from time to time" +
                        " with the blood of patroits and tyrants! Freedom is nothing but " +
                        "a chance to be better!");
            } else {
                // to show image
                // all you have to do is inflate the ViewStub for imageview
                ViewStub stub = (ViewStub) findViewById(R.id.viewstub_demo_image);
                stub.inflate();
                ImageView image = (ImageView) findViewById(R.id.viewstub_demo_imageview);
                image.setImageResource(R.mipmap.ic_launcher);
            }
        }
    }

    运行结果:

    使用的时候的注意事项:

    1. 某些布局属性要加在ViewStub而不是实际的布局上面,才会起作用,比如上面用的android:layout_margin*系列属性,如果加在 TextView上面,则不会起作用,需要放在它的ViewStub上面才会起作用。而ViewStub的属性在inflate()后会都传给相应的布 局。

    2.ViewStub之所以常称之为“延迟化加载”,是因为在教多数情况下,程序 无需显示ViewStub所指向的布局文件,只有在特定的某些较少条件下,此时ViewStub所指向的布局文件才需要被inflate,且此布局文件直 接将当前ViewStub替换掉,具体是通过viewStub.infalte()或 viewStub.setVisibility(View.VISIBLE)来完成;

    3.正确把握住ViewStub的应用场景非常重要,正如如1中所描述需求场景下,使用ViewStub可以优化布局;

    4.对ViewStub的inflate操作只能进行一次,因为inflate的 时候是将其指向的布局文件解析inflate并替换掉当前ViewStub本身(由此体现出了ViewStub“占位符”性质),一旦替换后,此时原来的 布局文件中就没有ViewStub控件了,因此,如果多次对ViewStub进行infalte,会出现错误信息:ViewStub must have a non-null ViewGroup viewParent。

    5.3中所讲到的ViewStub指向的布局文件解析inflate并替换掉当前 ViewStub本身,并不是完全意义上的替换(与include标签还不太一样),替换时,布局文件的layout params是以ViewStub为准,其他布局属性是以布局文件自身为准。

    6.ViewStub本身是不可见的,对 ViewStub setVisibility(..)与其他控件不一样,ViewStub的setVisibility 成View.VISIBLE或INVISIBLE如果是首次使用,都会自动inflate其指向的布局文件,并替换ViewStub本身,再次使用则是相 当于对其指向的布局文件设置可见性

     

     

    展开全文
  • Android之ViewStub的简单使用

    千次阅读 2019-03-19 19:17:01
    1.viewstub就是动态加载试图;也就是在我们的app启动绘制页面的时候,他不会绘制到view树中;当在代码中执行inflate操作后,她才会被添加到试图中。其实ViewStub就是一个宽高都为0的一个View,它默认是不可见的,...

    1.viewstub就是动态加载试图;也就是在我们的app启动绘制页面的时候,他不会绘制到view树中;当在代码中执行inflate操作后,她才会被添加到试图中。其实ViewStub就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才 会将其要装载的目标布局给加载出来,从而达到延迟加载的效果,这个要被加载的布局通过android:layout属性来设置。最终目的是把app加载页面的速度提高了,使用户体验更好。

    2.看一个简单的demo

    viewstub.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/inflatedStart"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/hello_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:text="DATA EMPTY!"/>
    
    </android.support.constraint.ConstraintLayout>
    activity_myviewstub.xml
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="inflate"
            android:text="inflate" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="setData"
            android:text="setdata"/>
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="hide"
            android:text="hide"/>
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="show"
            android:text="show"/>
    
        <ViewStub
            android:id="@+id/vs"
            android:inflatedId="@+id/inflatedStart"
            android:layout="@layout/viewstub"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    MyViewStubActivity.java
    package com.ysl.myandroidbase.viewstub;
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.constraint.ConstraintLayout;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.view.ViewStub;
    import android.widget.TextView;
    
    import com.ysl.myandroidbase.R;
    
    public class MyViewStubActivity extends AppCompatActivity {
        private ViewStub viewStub;
        private TextView textView;
        private View inflate;
        private ConstraintLayout constraintLayout;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_myviewstub);
            viewStub = findViewById(R.id.vs);
            //textView  = (TextView) findViewById(R.id.hello_tv);空指针,因为viewstub没有inflate
        }
        public  void inflate(View view){
            if (inflate == null) {//inflate只会进行一次,当第二次调用的时候,就会抛异常;也可以try catch进行处理
                inflate = viewStub.inflate();
    
                constraintLayout = findViewById(R.id.inflatedStart);
                System.out.println(constraintLayout);
    
                System.out.println("viewStub-------->"+viewStub);
                textView  = viewStub.findViewById(R.id.hello_tv);//获取到的textview是空的;
                System.out.println("viewStub textView-------->"+textView);//null
    
                textView  = constraintLayout.findViewById(R.id.hello_tv);
                System.out.println("constraintLayout textView-------->"+textView);
    
                textView  = findViewById(R.id.hello_tv);
                System.out.println("textView-------->"+textView);
            }
        }
        public void setData(View view){
            if (constraintLayout != null) {
                textView = constraintLayout.findViewById(R.id.hello_tv);
                textView.setText("HAVE DATA !!!");
            }
        }
        public void hide(View view){
            viewStub.setVisibility(View.GONE);
    //        if (constraintLayout != null){
    //            constraintLayout.setVisibility(View.GONE);
    //        }
        }
        public void show(View view){
            viewStub.setVisibility(View.VISIBLE);
    //        if (constraintLayout != null){
    //            constraintLayout.setVisibility(View.VISIBLE);
    //        }
        }
    }
    

    3.当调用第二次inflate的时候,会报错:

    我们看一下这是为什么?进入viewStub.inflate();的源码:

    public View inflate() {
            final ViewParent viewParent = getParent();
    
            if (viewParent != null && viewParent instanceof ViewGroup) {
                if (mLayoutResource != 0) {
                    final ViewGroup parent = (ViewGroup) viewParent;
                    final View view = inflateViewNoAdd(parent);
                    replaceSelfWithView(view, parent);
    
                    mInflatedViewRef = new WeakReference<>(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");
            }
        }

    可以看到当viewParent为空或者不是viewgroup时才会报这个错误;那么第一次调用的时候,肯定是进去了;发现一个方法replaceSelfWithView(view,parent);view就是我们在布局文件中给viewstub指定的layout所引用的那个布局;parent就是getParent方法得到的,也就是acticity的填充布局LinearLayout;

    进去看一下:

    private void replaceSelfWithView(View view, ViewGroup parent) {
            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);
            }
        }

    可以发现parent.removeViewInLayout(this);把this就是viewstub从父布局linearlayout中移除了;parent.addView()就是把view(也就是我们引用的布局)添加到了父布局LinearLayout中。

    我们用layout inspector来查看一下:

    inflate前:可以看到viewstub是灰色的

    inflate后:可以看到viewstub直接被移除了,把引用布局直接放到view树里了。

    所以当我们第二次再调用inflate方法时,viewstub的parent已经为空了;就会抛出此异常;

    当调用textView = viewStub.findViewById(R.id.hello_tv);//获取到的textview是空的;

    而使用textView = findViewById(R.id.hello_tv);就可以直接拿到控件对象了;

    当实现引用布局的显示和隐藏时,测试发现使用viewstub的setVisibility()方法可以实现,这是为什么呢?;按理说使用constraintLayout.setVisibility()当然也可以;根据上面的view树结构来看,好像使用引用布局的setVisibility()方法更合理一些;

    下面我们再来看看viewstub的setVisibility()为什么也可以;跟进源码看看:

    源码中使用mInflatedViewRef获取到view,然后设置隐藏与显示;mInflatedViewRef是一个view的弱引用WeakReference<View>

    其实在上面的inflate方法中已经为其添加了mInflatedViewRef = new WeakReference<>(view);这个view就是viewstub中的引用布局;

    所以,使用viewstub可以实现相同的显示或隐藏效果;

    从上图的最后一个红色框中可以发现,假设现在我没有调用inflate方法,而是直接点击了show按钮;然后引用布局也可以绘制出来;这就是我在写demo的时候,直接上去点击show按钮,竟然也可以显示的原因。

     

     

    展开全文
  • ViewStub 和 include 中 根view设置宽高都等于 wrap_content的问题 如下: <ViewStub android:id="@+id/stub_normal" android:layout_width="match_parent" android:layout_height="wrap_co

    ViewStub 和 include 中 根view设置宽高都等于 wrap_content的问题
    如下:
    <ViewStub
    android:id="@+id/stub_normal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="10dp"
    android:layout="@layout/layout_pay_setting_normal" />

    这是我引用的布局文件 layout_pay_setting_normal.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:background="@color/color_ff"
            android:gravity="center_vertical"
            android:paddingLeft="15dp"
            android:paddingRight="15dp"
            android:orientation="vertical">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/default_view_cost"
                android:textColor="@color/color_33"
                android:textSize="14sp" />
    
            <EditText
                android:id="@+id/normal_cost"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@null"
                android:gravity="right|center_vertical"
                android:hint="@string/default_moment_cost"
                android:inputType="number"
                android:textColorHint="@color/color_99"
                android:textSize="14sp" />
    
            <TextView
                android:id="@+id/normal_unit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="秒/条"
                android:textColor="@color/color_33"
                android:textSize="14sp"
                android:visibility="gone" />
    </LinearLayout>
    

    以上根布局layout_height=”48dp”在viewstub 引用后失效,后来我在外面又套了层布局(如下代码)就没问题了:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:background="@color/color_ff"
            android:gravity="center_vertical"
            android:paddingLeft="15dp"
            android:paddingRight="15dp">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/default_view_cost"
                android:textColor="@color/color_33"
                android:textSize="14sp" />
    
            <EditText
                android:id="@+id/normal_cost"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:background="@null"
                android:gravity="right|center_vertical"
                android:hint="@string/default_moment_cost"
                android:inputType="number"
                android:textColorHint="@color/color_99"
                android:textSize="14sp" />
    
            <TextView
                android:id="@+id/normal_unit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="秒/条"
                android:textColor="@color/color_33"
                android:textSize="14sp"
                android:visibility="gone" />
        </LinearLayout>
    
    </LinearLayout>

    猜测原因:这可能是因为在ViewStub或者include 进行inflate时(尤其是ViewStub设置了高为wrap_content),无论最外层布局宽高多大,都按照wrap_content来处理的,因此,除非子 view有个明确的高度,否则最外层宽高设置将失效。

    修正后的layout_pay_setting_normal.xml中,计算view大小时测得子 view高度为48dp,因此ViewStub inflate后的view需要的高度为48dp,除非ViewStub自己重新设置layout_height的高度

    展开全文
  • 使用ViewStub来提高加载性能吧!

    万次阅读 2016-12-08 12:49:57
    使用ViewStub提高性能

    什么是ViewStub?

    ViewStub其实本质上也是一个View,其继承关系如图所示:
    ViewStub继承关系

    为什么ViewStub可以提高加载性能?

    ViewStub使用的是惰性加载的方式,即使将其放置于布局文件中,如果没有进行加载那就为空,不像其它控件一样只要布局文件中声明就会存在。
    那ViewStub适用于场景呢?通常用于网络请求页面失败的显示。一般情况下若要实现一个网络请求失败的页面,我们是不是使用两个View呢,一个隐藏,一个显示。试想一下,如果网络状况良好,并不需要加载失败页面,但是此页面确确实实已经加载完了,无非只是隐藏看不见而已。如果使用ViewStub,在需要的时候才进行加载,不就达到节约内存提高性能的目的了吗?

    ViewStub的加载原理

    ViewStub只能加载一次,重复加载会导致异常,这是因为ViewStub只要加载过一次,其自身就会被移除,把并自身所包含的内容全部传给父布局。来张图感受一下
    ViewStub的加载原理

    ViewStub如何使用

    • 父布局
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:orientation="vertical"
        tools:context="com.example.administrator.myviewstub.MainActivity">
    
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="inflate"
            android:text="inflate" />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:onClick="setData"
            android:text="setdata"/>
        <ViewStub
            android:id="@+id/vs"
            android:layout="@layout/viewstub"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>

    可以看到ViewStub又引用了另外一个布局。

    • ViewStub布局
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/hello_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="DATA EMPTY!"/>
    </FrameLayout>
    • MainActivity
    public class MainActivity extends AppCompatActivity {
        private ViewStub viewStub;
        private TextView textView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            viewStub = (ViewStub) findViewById(R.id.vs);
            //textView  = (TextView) findViewById(R.id.hello_tv);空指针
        }
        public  void inflate(View view){
            viewStub.inflate();
            //textView  = (TextView) viewStub.findViewById(R.id.hello_tv);空指针
            textView  = (TextView) findViewById(R.id.hello_tv);
        }
        public void setData(View view){
            textView.setText("DATA!!");
    
        }
    }

    注意:这里有几个坑,前面我们说了ViewStub只有在初始化之后才会存在,所以第一个注释中的空指针是因为ViewStub还未初始化。那第二个注释中的空指针是怎么回事呢?前面我们也说了,ViewStub在加载完成之后会移除自身,并把自身的内容转给父布局,所以此时viewStub中的内容已经不存在了,textView已经是父布局的东西了,所以不能使用viewStub来findViewById。另外,前面我们说了ViewStub只能加载一次,若调用两次inflate()的话会导致异常。
    加载异常

    为了验证所得出的结论是不是正确的,我截了两张ViewStub加载前后的图。

    • 加载前:
      加载前

    从图中可以看到ViewStub还没加载,是灰色的。

    • 加载后:
      加载后

    当点击了INFLATE之后,可以看到,ViewStub消失了,取而代之的是一个FrameLayout,其中包含了一个AppCompatTextView(ps.其实就是TextView,只是Google在5.0之后提供了向前兼容,就好比AppCompatActivity和Activity一样)。咳,这个FrameLayout是不是很眼熟,没错!就是我们之前写的ViewStub的布局,忘记的童鞋翻回去看看。

    • 顺便验证一下TextView是不是能用,点击SETDATA:
      这里写图片描述

    没有问题。

    关于这个图是怎么来的,童鞋们只要点击Android Montior中的Layout Inspector就行啦,就是介个:
    Layout Inspector
    感兴趣的童鞋可以自己去试试。

    源码分析

    ViewStub是如何实现的呢,接下来我们来一探究竟:

     public View inflate() {
            final ViewParent viewParent = getParent();//获取父View
    
            if (viewParent != null && viewParent instanceof ViewGroup) {
            //若父不是ViewGroup就会抛出异常("ViewStub must have a non-null ViewGroup viewParent")
                if (mLayoutResource != 0) {
                //这个就是ViewStub只能加载一次的原因,第二次加载则抛出异常(throw new IllegalArgumentException("ViewStub must have a valid layoutResource"))
                    final ViewGroup parent = (ViewGroup) viewParent;
                    final LayoutInflater factory;
                    if (mInflater != null) {
                        factory = mInflater;
                    } else {
                        factory = LayoutInflater.from(mContext);
                    }
                    final View view = factory.inflate(mLayoutResource, parent,
                            false);
                    //创建一个View,这个View为ViewStub的内容,mLayoutResource为ViewStub自身的Layout资源文件id
                    if (mInflatedId != NO_ID) {
                        view.setId(mInflatedId);
                        //若mInflatedId存在,则将id重新赋值给新的View
                    }
    
                    final int index = parent.indexOfChild(this);
                    parent.removeViewInLayout(this);
                    //通过父布局将ViewStub移除
                    final ViewGroup.LayoutParams layoutParams = getLayoutParams();
                    if (layoutParams != null) {
                        parent.addView(view, index, layoutParams);
                    } else {
                        parent.addView(view, index);
                    }
                    //将ViewStub中的内容添加到父容器中
                    mInflatedViewRef = new WeakReference<View>(view);
                    //设置为弱引用,当VIewStub设置为空时将立即执行GC
                    if (mInflateListener != null) {
                        mInflateListener.onInflate(this, view);
                    }
    
                    return view;
                    //最后将View返回出去
                } else {
                    throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
                }
            } else {
                throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
            }
        }

    ViewStub中还有一个setVisibility(int visibility)值得我们注意:

    public void setVisibility(int visibility) {
            if (mInflatedViewRef != null) {
                View view = mInflatedViewRef.get();
                //拿到关联的Layout
                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();
                }
            }
        }

    可以看到,ViewStub若之前没有进行inflate,setVisibility(View.VISIBLE)或setVisibility(View.INVISIBLE)会自动先进行加载,而加载之后可以设置显示和隐藏。并且ViewStub设置的不是自己,而是拿到关联的那个Layout设置visible。ViewStub此时并未销毁,所以建议初始化后将其设置为空。

    展开全文
  • 这时候我们该怎么弄,本编文章将会介绍include、merge和ViewStub标签的用法供大家参考学习…!include标签include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,也是平常我们设计布局时用...
  • ViewStub用法

    2018-08-06 17:30:38
    可以为ViewStub指定一个布局,在Inflate布局的时候,只有 ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向 的布局就会被Inflate和实例化,然后ViewStub的...
  • 利用ViewStub显示和隐藏布局 运用View.VISIBLE和View.GONE去改变布局的可见性.
  • ViewStub

    千次阅读 2016-11-06 11:13:55
    由于最近正在封装下拉刷新上拉加载的库,为了进一步的优化ui,所以学习了下ViewStub,这里转载别人的blog分享给大家.  在Android开发中,经常会遇到这样的情况,在程序运行过程中动态的根据当前条件来决定是否显示某个...
  • 一、使用include加载布局 MainActivity的布局文件如下所示: &amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt; &amp;lt;LinearLayout xmlns:android=&...
  • 在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在代码中动态的更改...
  • ViewStub使用

    2019-05-21 18:26:00
    今天写一下 ViewStub ,内容很简单! ViewStub 是一个不可见的,没有尺寸,不会绘制任何东西的布局。主要用于实现 View 的延迟加载,可以避免浪费资源,减少布局的绘画,只有需要的时候才会加载。 在 ViewStub 加载...
  • Android小记:ViewStub使用

    千次阅读 2015-08-09 22:45:44
    ViewStub使用示例 mainActivity如下: import android.os.Bundle; import android.view.View; import android.view.ViewStub; import android.view.View.OnClickListener; impo
  • android ViewStub使用

    2016-10-11 13:48:36
    android ViewStub使用
  • android控件:ViewStub用法 在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局。那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View....

空空如也

1 2 3 4 5 ... 20
收藏数 8,317
精华内容 3,326
关键字:

viewstub