介绍
复杂视图会耗尽 RAM 并降低 Android 应用程序的性能。如果一个视图很少使用,你应该考虑延迟它的渲染,直到你的应用程序需要它。一种方法是使用 ViewStub 视图。
ViewStub 的膨胀成本非常低,因此它通常可以用作复杂视图的存根。
目标
在本教程结束时,您将学到:
如何使用 ViewStub 延迟加载视图。
先决知识
基本的Android开发知识。
所需工具
安卓工作室。
项目设置
要按照本教程进行操作,请执行以下步骤:
使用默认的 Empty Activity 创建一个新的 Android 项目。
删除“ Hello World ” TextView。
ViewStub 概念概述
ViewStub 膨胀起来很便宜,因为它是不可见的并且具有零维度。在开发时,它引用另一个具有该android:layout属性的布局文件。它引用的 XML 文件不一定必须是LayoutX类(FrameLayout、ConstraintLayout 等)之一。任何视图都可以。
当一个 ViewStub 膨胀时,底层布局会继承 ViewStub 的布局参数并替换父布局中的 ViewStub。在膨胀id后尝试引用 ViewStub 时应该小心,因为应用程序将抛出NullPointerException。
有两种常见的方法来膨胀 ViewStub:
将 设置visibility为常量View.VISIBLE。setVisibility()如果您使用的是 Java,请使用方法。
inflate()从 ViewStub 对象调用该函数。
我们将直接在本教程中设置可见性,因为它是 Kotlin 上最易读的选项。
创建要存根的视图
首先,让我们从创建一个供 ViewStub 引用的视图开始。在本教程中,我们将只使用Widget ProgressBar。
progress_bar.xml在res/layout其中创建一个仅包含 ProgressBar 本身的文件。
右键单击布局目录。
新的
布局资源文件。
使用progress_bar的文件名。
将根元素更改为ProgressBar.
选择确定。
进度条.png
的 XML 内容progress_bar.xml应该是这样的。
<?xml version=”1.0″ encoding=”utf-8″?>
<ProgressBar xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”match_parent”>
</ProgressBar>
创建视图存根
现在我们已经准备好了 ProgressBar 视图,让我们添加一个 ViewStub 作为它的轻量级占位符。
activity_main.xml在设计图面中打开。
在 下Palette/Containers,将一个新ViewStub拖入ConstraintLayout.
当提示输入要存根的资源时,选择progress_bar。
点击确定。
viewstub.png
activity_main.xml在代码视图中打开,您将看到android:layout在 ViewStub 标记内调用的属性,如ViewStub 概念概述部分所述。
<ViewStub
android:id=”@+id/viewStub”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout=”@layout/progress_bar” />
切换回设计图面。
将底部、左侧和右侧约束添加到 ViewStub。都是零利润。不要忘记 ProgressBar 在运行时膨胀时也会继承这些约束。
下面是 ViewStub 约束的代码
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
添加触发器
为了激活布局膨胀,让我们向布局添加一个简单的按钮。
activity_main.xml在设计图面中打开。
从 中Palette/Buttons,将一个新 Button 拖入ConstraintLayout.
将其约束到 ConstraintLayout 的所有四个边,边距为零。
将 Button 的硬编码文本提取到单独的 String 资源。
将 ViewStub 的顶部约束到 Button 的底部。由于 ViewStub 维度在设计图面中不可选,因此切换到代码视图并将此属性添加到 ViewStub 标记。
app:layout_constraintTop_toBottomOf=”@id/button”
您的 Button 标签现在应如下所示。
<Button
android:id=”@+id/button”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/button”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />
如果我们想让我们的按钮做一些有用的事情,那么我们需要onClickListener给它添加一个。在 中MainActivity.kt,将下面的代码添加到onCreate().
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
findViewById<ViewStub>(R.id.viewStub).visibility = View.VISIBLE //ViewStub is killed after this
}
第一行尝试通过 找到 Button id。第二行更改visibilityViewStub 的 ,因此 ProgressBar 将被膨胀。
运行应用程序
我们现在已经完成了使用 ViewStub 的所有先决条件。是时候运行应用程序了。如果您还在正在运行的应用程序中添加了 Profiler,那么您还可以看到 CPU 使用率从0 %不断增加到5% 左右(取决于您的计算机/模拟器)。
ViewStubAnimation.gif
这进一步证明了这种视图应该只在需要时才加载。
NullPointerException 在销毁 ViewStub
请注意,如果您单击该按钮两次,那么您的应用程序将崩溃,因为您onClickListener仍在引用不再存在于视图层次结构中的同一个 ViewStub。
如果您不再需要 Button 或您的应用程序使用的任何触发器,那么您可以销毁 Button 本身。
另一种选择是简单地将elvis 运算符( ?)添加到您的findViewById()函数调用中,如下面的代码。
findViewById<ViewStub>(R.id.viewStub)?.visibility = View.VISIBLE
解决方案代码
主活动.kt
package com.example.daniwebviewstub
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.ViewStub
import android.widget.Button
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
findViewById<ViewStub>(R.id.viewStub)?.visibility = View.VISIBLE //ViewStub is killed after this
}
}
}
活动_main.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmlns:app=”http://schemas.android.com/apk/res-auto”
xmlns:tools=”http://schemas.android.com/tools”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
tools:context=”.MainActivity”>
<Button
android:id=”@+id/button”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”@string/button”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />
<ViewStub
android:id=”@+id/viewStub”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout=”@layout/progress_bar”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintEnd_toEndOf=”parent”
app:layout_constraintStart_toStartOf=”parent”
app:layout_constraintTop_toBottomOf=”@id/button” />
</androidx.constraintlayout.widget.ConstraintLayout>
进度条.xml
<?xml version=”1.0″ encoding=”utf-8″?>
<ProgressBar xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”match_parent”>
</ProgressBar>
字符串.xml
<resources>
<string name=”app_name”>Daniweb ViewStub</string>
<string name=”button”>Button</string>
</resources>
概括
恭喜!您已经学习了如何在 Android Native 上使用 ViewStub。完整的项目代码可以在
请登录之后再进行评论