在 Android 中使用 Shimmer 实现内容占位符动画

androidmobile developmentapps/applications更新于 2026/2/8 23:07:17

简介

什么是在 Android 中使用 Shimmer 实现内容占位符动画?

在 Android 应用程序中,我们可以使用多种不同的方式显示加载指示器,例如进度条、水平加载条等等。同样,Shimmer View 也是一种加载指示器,我们可以使用它在应用程序中显示加载屏幕。

Shimmer View 的实现

我们将创建一个简单的应用程序,在其中从 API 加载一些数据,并添加一个加载指示器,我们将使用 Shimmer 在其中添加一个内容占位符动画。我们将按照分步指南在我们的 Android 应用程序中实现 Shimmer View。

步骤 1:在 Android Studio 中创建新项目

如下图所示,导航到 Android Studio。在下面的屏幕中,点击"新建项目"创建一个新的 Android Studio 项目。

点击"新建项目"后,您将看到下面的屏幕。

在此屏幕中,我们只需选择"空活动"并点击"下一步"。点击"下一步"后,您将看到以下屏幕。

在此屏幕中,我们只需指定项目名称。然后会自动生成包名。

注意 − 请确保选择 Kotlin 作为语言。

完成所有设置后,点击"完成"即可创建一个新的 Android Studio 项目。

项目创建完成后,我们将看到两个打开的文件,即 activity_main.xml 和 MainActivity.kt 文件。

步骤 2:添加依赖项以使用 Shimmer View 和 Volley

导航至 app>Gradle Scripts>build.gradle file>dependencies 部分,并添加以下依赖项。代码中添加了注释,以便您详细了解。

// volley 用于 JSON 解析。
实现 'com.android.volley:volley:1.2.0'
// shimmer 用于显示加载指示
实现 'com.facebook.shimmer:shimmer:0.5.0'

添加依赖项后,只需同步您的项目即可安装。

步骤 3:使用 activity_main.xml。

导航到 activity_main.xml。如果此文件不可见,请在左侧窗格中导航至 app>res>layout>activity_main.xml 以打开此文件。打开此文件后,向其中添加以下代码。代码中添加了注释,以便您详细了解。

语法

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">

   <!-- creating a relative layout on below line-->
   <RelativeLayout
      android:id="@+id/idRLView"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:visibility="gone">

      <!-- creating an image view for image on below line-->
      <ImageView
         android:id="@+id/idIVImage"
         android:layout_width="200dp"
         android:layout_height="100dp"
         android:layout_centerHorizontal="true"
         android:layout_marginTop="150dp"
         android:src="@drawable/gptimg" />

      <!-- creating text view for name on below line-->
      <TextView
         android:id="@+id/idTVTitle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/idIVImage"
         android:layout_centerHorizontal="true"
         android:layout_margin="10dp"
         android:gravity="center"
         android:padding="4dp"
         android:text="Title"
         android:textAlignment="center"
         android:textColor="@color/black"
         android:textSize="20sp"
         android:textStyle="bold" />

      <!-- creating a text view for description on below line-->
      <TextView
         android:id="@+id/idTVDescription"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/idTVTitle"
         android:layout_centerHorizontal="true"
         android:layout_margin="10dp"
         android:gravity="center"
         android:padding="4dp"
         android:text="Description"
         android:textAlignment="center"
         android:textColor="@color/black"
         android:textSize="15sp"
         android:textStyle="bold" />

      <!-- creating an address for text view on below line-->
      <TextView
         android:id="@+id/idTVAddress"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/idTVDescription"
         android:layout_centerHorizontal="true"
         android:layout_marginStart="10dp"
         android:layout_marginEnd="10dp"
         android:gravity="center"
         android:padding="4dp"
         android:text="Address"
         android:textAlignment="center"
         android:textColor="@color/black"
         android:textSize="15sp"
         android:textStyle="normal" />

   </RelativeLayout>

   <!-- creating a shimmer frame layout on below line-->
   <com.facebook.shimmer.ShimmerFrameLayout
      android:id="@+id/shimmerLayout"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:animateLayoutChanges="true"
      android:animationCache="true"
      app:shimmer_repeat_mode="restart"
      app:shimmer_shape="radial">

      <!--creating a relative layout on below line-->
      <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">

         <!--creating an image view on below line-->
         <ImageView
            android:id="@+id/idIVSImg"
            android:layout_width="200dp"
            android:layout_height="100dp"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="150dp"
            android:background="#B3B3B3" />

         <!-- creating an empty text view on below line-->
         <TextView
            android:id="@+id/idTVSTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/idIVSImg"
            android:layout_centerHorizontal="true"
            android:layout_marginStart="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginEnd="10dp"
            android:layout_marginBottom="10dp"
            android:background="#B3B3B3"
            android:gravity="center"
            android:padding="4dp"
            android:textAlignment="center"
            android:textSize="20sp"
            android:textStyle="bold" />

         <!-- creating an empty text view on below line-->
         <TextView
            android:id="@+id/idTVSDescription"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/idTVSTitle"
            android:layout_centerHorizontal="true"
            android:layout_margin="10dp"
            android:background="#B3B3B3"
            android:gravity="center"
            android:padding="4dp"
            android:textAlignment="center"
            android:textSize="15sp"
            android:textStyle="bold" />

         <!-- creating an empty text view for address on below line-->
         <TextView
            android:id="@+id/idTVSAddress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/idTVSDescription"
            android:layout_centerHorizontal="true"
            android:layout_marginStart="10dp"
            android:layout_marginEnd="10dp"
            android:background="#B3B3B3"
            android:gravity="center"
            android:padding="4dp"
            android:textAlignment="center"
            android:textColor="@color/black"
            android:textSize="15sp"
            android:textStyle="bold" />

      </RelativeLayout>
   </com.facebook.shimmer.ShimmerFrameLayout>
</RelativeLayout>

说明− 在上面的代码中,我们创建了一个 RelativeLayout 作为根布局,并在该 RelativeLayout 内部创建了一个 RelativeLayout 和一个 Shimmer Frame Layout。子 RelativeLayout 包含我们需要向用户显示的实际 UI,其中包含文本视图和图像视图。此外,还有一个 Shimmer Frame Layout,我们在其中创建了图像视图和文本视图。

最初,我们将 RelativeLayout 的可见性设置为"消失",将 Shimmer Frame Layout 的可见性设置为"可见"。一旦收到 API 的响应,我们就会将 RelativeLayout 的可见性更改为"可见",将 Shimmer Layout 的可见性更改为"消失"。

步骤 3:使用 MainActivity.kt

导航到 MainActivity.kt。如果此文件不可见,请打开此文件。在左侧窗格中,导航至 app>java>您的应用包名称>MainActivity.kt 并打开此文件。打开此文件后,添加以下代码。代码中添加了注释,方便您详细了解。

package com.example.gptapp

import android.os.Bundle
import android.util.Log
import android.view.ContextMenu
import android.view.MenuItem
import android.view.View
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.facebook.shimmer.ShimmerFrameLayout
import com.squareup.picasso.Picasso
import kotlin.math.log

class MainActivity : AppCompatActivity() {
   // 在下面一行创建变量。
   lateinit var originRL: RelativeLayout
   lateinit var shimmerView: ShimmerFrameLayout
   lateinit var logoIV: ImageView
   lateinit var nameTV: TextView
   lateinit var addressTV: TextView
   lateinit var descTV: TextView

   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // 使用下一行中的 ID 初始化所有变量。
        originRL = findViewById(R.id.idRLView)
        shimmerView = findViewById(R.id.shimmerLayout)
        logoIV = findViewById(R.id.idIVImage)
        nameTV = findViewById(R.id.idTVTitle)
        addressTV = findViewById(R.id.idTVAddress)
        descTV = findViewById(R.id.idTVDescription)
        // 调用方法从 API 读取数据。
        readData()
   }
   private fun readData() {
        // 在下面一行中创建一个用于请求队列的变量。
        val queue: RequestQueue = Volley.newRequestQueue(applicationContext)
        // 在下面一行中创建一个用于 aoi url 的变量。
        val apiUrl = "https://www.jsonkeeper.com/b/AR3Q"
        // 创建一个 JSON 对象请求,并将 get 方法传递给 API 以获取响应。
        val request = JsonObjectRequest(Request.Method.GET, apiUrl, null, { response ->
        // 下面一行从我们的 JSON 对象中提取数据。
        val title = response.getString("name")
        val imgUrl = response.getString("imgUrl")
        val description = response.getString("description")
        val address = response.getString("address")
        // 下面一行更改 shimmer 视图和原始相对布局的可见性。
        shimmerView.visibility = View.GONE
        originRL.visibility = View.VISIBLE
        // 下面一行将数据设置为我们的文本视图和图像视图。
        nameTV.text = title
        Picasso.get().load(imgUrl).into(logoIV)
        descTV.text = description
        addressTV.text = address

      }, { error ->
         // 如果我们未能从 API 获得响应,则显示一条 toast 消息。
         Toast.makeText(this@MainActivity, "Fail to get response", Toast.LENGTH_SHORT)
         .show()
      })
      // 最后,我们将
      // 请求添加到队列中。
      queue.add(request)
   }
}

说明− 在 MainActivity.kt 文件中,我们首先为所有视图(例如相对布局、文本视图以及图像视图)创建变量。然后在 onCreate 方法中,我们使用它们的 ID 初始化这些视图。

初始化这些视图后,我们将创建一个名为 readData() 的单独方法。在该方法中,我们将进行 API 调用以从 API 中读取数据。在 readData() 方法中,我们为 requestQueue 创建一个变量,用于发出 API 调用请求。之后,我们创建一个变量来存储 API 的 URL。然后,我们发出一个 Json 对象请求来发出 API 调用。在这个 JSON 对象的请求方法中,有两个方法,一个是 response,用于从 API 获取响应;另一个是 Error,如果 API 未能返回任何响应,它将返回一个错误。在 response 方法中获取响应后,我们将从响应中提取数据,并将该数据设置到文本视图和图像视图中。之后,我们将 Shimmer 视图的可见性更改为"消失",并将相对布局可见性更改为"可见",以便向用户显示实际的 UI。在 error 方法中,我们显示一条 Toast 消息,向用户显示错误。最后,我们将请求添加到队列中以进行 API 调用。

添加上述代码后,现在只需点击顶部栏中的绿色图标即可在移动设备上运行我们的应用程序。

注意− 确保您已连接到真实设备或模拟器。

结论

在以上教程中,我们了解了 Android 中的 Toast 消息是什么,以及如何使用它在 Android 应用程序中向用户显示短消息。我们学习了如何创建一个新的 android studio 项目,然后研究了 UI,并为我们的按钮添加了一个功能,以便在用户点击按钮时显示一个 toast 消息。


相关文章