Android之ViewStub的简单使用

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

大家好,又见面了,我是你们的朋友全栈君。

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的时候,会报错:

Android之ViewStub的简单使用

我们看一下这是为什么?进入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是灰色的

Android之ViewStub的简单使用

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

Android之ViewStub的简单使用

所以当我们第二次再调用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()为什么也可以;跟进源码看看:

Android之ViewStub的简单使用

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

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

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

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

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/153944.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ubuntu更改内核版本_ubuntu切换内核进入系统

    ubuntu更改内核版本_ubuntu切换内核进入系统背景新安装的ubuntu20内核版本是5.8,对于我个人来说太高了,需要安全地更换内核到低版本。如果是需要内核升级的,本文也适用。多内核并存或者删除其他内核方法同样适用。一、检查自己的内核版本uname-aLinuxlinux5.4.0-66-generic#74-UbuntuSMPWedJan2722:54:38UTC2021x86_64x86_64x86_64GNU/Linux我的内核也就是5.4二、下载所需内核选择1:安装apt最新的内核版本sudo

    2022年8月23日
    67
  • java adminlte 使用_AdminLTE的使用

    java adminlte 使用_AdminLTE的使用第一次听说这个模板,留着以后用1.AdminLTE的必要配置文件2.自定义主题样式(1)在body中设置class。skin-blue:主题颜色,如果引入了_all-skins.min.css,有很多颜色可以选择,如左图,设置为skin-blue默认就为右图的主题样式。sidebar-mini:在AdminLTE.css中可以找到。(2)wrapper设置:AdminLTE…

    2022年7月27日
    7
  • list转json字符串

    list转json字符串使用Gson把list转成json字符串com.google.gson.Gson@GetMapping(“/valueTest”)publicStringvalueTest(){List<Map<String,Object>>list=newArrayList<>();Map<String,Object>map1=newHashMap<>();map1

    2022年10月18日
    3
  • Please upgrade the installed version of powershell to the minimum required version and run the comma…

    Please upgrade the installed version of powershell to the minimum required version and run the comma…

    2021年10月28日
    46
  • linux 网口_网络管理员网址

    linux 网口_网络管理员网址Linux12:网络管理文章目录一.网络接口名称规则1.认识网卡2.修改网卡配置文件3.主机名4.网络测试工具一.网络接口名称规则计算机与外界通信的前提是:有网卡(网络适配器NAT)注意:虚拟机的总内存,不能超过真机服务器和客户机:谁提供服务,谁就是服务器1.认识网卡#ls /etc/sysconfig/network-scripts/补充:网络管理器NetworkManager,动态网络的控制器与配置系统,它用于当网络设备可用时保持设备和连接开启并激活查看该服务的运行状况:#

    2022年8月9日
    7
  • 华为手机切换屏幕效果_华为p40页面切换效果怎么换

    华为手机切换屏幕效果_华为p40页面切换效果怎么换通过style自定义Activity切换动画在华为上失效问题

    2022年4月22日
    204

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号