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按钮,竟然也可以显示的原因。

 

 

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 关于Delay函数的思考

    关于Delay函数的思考可能很多人对延时函数的使用并不排斥,但是我个人觉得这是非常不符合软件的本质的。软件的本质是将现实中的各种行为抽象。以现实中人的活动为例,人在同一时刻是可以实时响应很多事情的,而Delay函数的出现相当于给CPU上了刹车

  • 介绍书中人物(笼中月介绍)

    远程对象的基础接口,是一个为了在执行进程中和进程间调用时的高性能,而设计的轻量级远程调用机制的核心部分。这个接口描述了和远程对象交互的抽象协议。不要直接实现这个接口,而是通过继承 Binder来实现。IBinder的关键API是与 Binder.onTransact() 相匹配的transact() .这个方法分别允许你给IBinder对象发出一个请求,并接收一个进入一个Binde

  • linux 查看igmp类型,Linux IGMP 学习笔记 之一 IGMP协议格式

    linux 查看igmp类型,Linux IGMP 学习笔记 之一 IGMP协议格式一、IGMP定义及分类IGMP:INTERNET组管理协议,与广播最大的不同是,IGMP允许每一个网络设备决定是否参与到一个特定的多播群组中。IGMP的ip地址,组播ip地址的范围为224.0.0.0-239.255.255.255。其中224.0.0.1代表子网上的所有计算机,224.0.0.2代表子网上一、IGMP定义及分类IGMP:INTERNET组管理协议,与广播最大的不同是,IGMP…

  • 高清视频编码格式_如何将高清视频转化为蓝光

    高清视频编码格式_如何将高清视频转化为蓝光收藏于2012-01-09迁移自个人百度空间—————————高清视频编码最常用的编码格式是MPEG2-TS、MPEG4、H.264和VC-1这四种算法。          MPEG2由MPEG(MovingPictureExpertsGroup)运动图像专家组制定,这是国际标准化组织(ISO)于1988年成立的专责制定有关运动压缩编码标…

  • J2EE之ServletContext读取资源文件

    J2EE之ServletContext读取资源文件

  • 小米手机解BL锁、线刷详细教程,适用于小米全系列手机[通俗易懂]

    小米手机解BL锁、线刷详细教程,适用于小米全系列手机[通俗易懂][教程]小米手机解BL锁、线刷详细教程,适用于小米全系列手机这几天看到论坛里很多人在问怎么线刷,下面我就做个详细的线教程大家看一下高手别喷我哈此教程只适合刷官方MIUI包进入正题。第一步:解BL锁1.浏览器打开申请解锁小米手机点击立即解锁,然后再点击下载解锁工具,下载后保存到电脑也可以点击这里立即下载2.解压后双击miflash_unlock.exe打开手机解锁工具V3.33.点同意,然后登陆帐号,手机会检测您的帐号是否可以解锁,如果不支持点击申请解锁,好像是大约一周左右可以通过申

发表回复

您的电子邮箱地址不会被公开。

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