ProgressBar(进度条)

ProgressBar 是 Android 开发中用于显示任务进度或加载状态的 View 组件,广泛应用于加载、下载或异步任务场景。它支持水平进度条、圆形进度条(Spinner)等多种样式,适合直观展示操作进度。本教程基于 Android Studio(截至 2025 年 9 月,Koala 2024.1.1),详细讲解 ProgressBar 的概念、属性、使用方法、示例代码和最佳实践,结合 XML 和 Jetpack Compose,适合初学者和需要深入理解的开发者。


1. ProgressBar 概念

  • 定义ProgressBar 是一个用于显示进度的 UI 组件,继承自 View,可展示确定进度(如下载百分比)或不确定进度(如加载动画)。
  • 作用
  • 显示任务进度(如文件下载、数据加载)。
  • 提供视觉反馈,增强用户体验。
  • android.widget.ProgressBar(或 androidx.core.widget.ContentLoadingProgressBar 推荐用于兼容性)。
  • 特点
  • 支持水平(Horizontal)和圆形(Indeterminate)两种模式。
  • 可自定义样式、颜色和动画。
  • 支持动态更新进度。
  • 局限
  • 默认样式较简单,复杂效果需自定义 Drawable。
  • 性能敏感场景需优化(如避免频繁更新)。

2. ProgressBar 核心属性

以下是 ProgressBar 的常用 XML 属性(res/layout/ 中定义):

属性描述示例
android:progress当前进度(0-maxandroid:progress="50"
android:max最大进度值android:max="100"
android:indeterminate是否为不确定模式(循环动画)android:indeterminate="true"
android:progressTint进度条颜色android:progressTint="@color/purple_500"
android:progressBackgroundTint背景颜色android:progressBackgroundTint="@color/gray"
android:layout_width宽度(水平模式推荐 match_parentandroid:layout_width="match_parent"
android:contentDescription无障碍描述android:contentDescription="@string/progress_desc"
style进度条样式style="@style/Widget.AppCompat.ProgressBar.Horizontal"
  • 样式
  • ?android:attr/progressBarStyle: 默认圆形(Spinner)。
  • ?android:attr/progressBarStyleHorizontal: 水平进度条。
  • 不确定模式indeterminate="true" 显示循环动画,适合未知时长的任务。
  • 注意
  • 使用 dp 单位确保适配。
  • 为无障碍添加 contentDescription

3. ProgressBar 使用

ProgressBar 可通过 XML 或代码定义,以下展示两种方式,并结合 Jetpack Compose。

3.1 XML 布局中使用

以下是一个下载进度界面,使用水平 ProgressBar。

<!-- Label -->
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/download_label"
    android:textSize="18sp" />

<!-- ProgressBar -->
<ProgressBar
    android:id="@+id/downloadProgress"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:max="100"
    android:progress="0"
    android:progressTint="@color/purple_500"
    android:progressBackgroundTint="@color/gray"
    android:contentDescription="@string/progress_desc"
    android:layout_marginTop="16dp" />

<!-- Progress Text -->
<TextView
    android:id="@+id/progressText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/progress_initial"
    android:textSize="16sp"
    android:layout_marginTop="8dp" />

<!-- Start Button -->
<Button
    android:id="@+id/startButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/start_download"
    android:layout_marginTop="16dp" />
  • 资源文件res/values/strings.xml):
    ProgressBar App Download Progress Download progress bar Progress: 0% Start Download
  • 资源文件res/values/colors.xml):
    #6200EE #CCCCCC
  • ActivityProgressActivity.kt):

    package com.example.myapp

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

class ProgressActivity : AppCompatActivity() {
private var progress = 0
private val handler = Handler(Looper.getMainLooper())

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_progress)

    val downloadProgress: ProgressBar = findViewById(R.id.downloadProgress)
    val progressText: TextView = findViewById(R.id.progressText)
    val startButton: Button = findViewById(R.id.startButton)

    startButton.setOnClickListener {
        progress = 0
        downloadProgress.progress = 0
        progressText.text = getString(R.string.progress_initial)

        // 模拟进度更新
        handler.post(object : Runnable {
            override fun run() {
                if (progress < 100) {
                    progress += 10
                    downloadProgress.progress = progress
                    progressText.text = "Progress: $progress%"
                    handler.postDelayed(this, 1000)
                }
            }
        })
    }
}

override fun onDestroy() {
    super.onDestroy()
    handler.removeCallbacksAndMessages(null) // 清理 Handler
}

}

  • 效果
  • 水平 ProgressBar 显示下载进度,初始 0%。
  • 点击“Start Download”按钮,模拟进度每秒增加 10%,更新 TextView。

3.2 代码中使用

动态创建 ProgressBar:

package com.example.myapp

import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.widget.Button
import android.widget.LinearLayout
import android.widget.ProgressBar
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class ProgressActivity : AppCompatActivity() {
private var progress = 0
private val handler = Handler(Looper.getMainLooper())

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // 创建 LinearLayout
    val layout = LinearLayout(this).apply {
        orientation = LinearLayout.VERTICAL
        layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.MATCH_PARENT
        )
        setPadding(16, 16, 16, 16)
        gravity = android.view.Gravity.CENTER
    }

    // 创建 Label
    val label = TextView(this).apply {
        text = getString(R.string.download_label)
        textSize = 18f
    }

    // 创建 ProgressBar
    val progressBar = ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal).apply {
        id = R.id.downloadProgress
        layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.WRAP_CONTENT
        ).apply { topMargin = 16 }
        max = 100
        progress = 0
        progressTintList = ContextCompat.getColorStateList(context, R.color.purple_500)
        progressBackgroundTintList = ContextCompat.getColorStateList(context, R.color.gray)
        contentDescription = getString(R.string.progress_desc)
    }

    // 创建 Progress Text
    val progressText = TextView(this).apply {
        id = R.id.progressText
        text = getString(R.string.progress_initial)
        textSize = 16f
        layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT
        ).apply { topMargin = 8 }
    }

    // 创建 Start Button
    val startButton = Button(this).apply {
        id = R.id.startButton
        text = getString(R.string.start_download)
        layoutParams = LinearLayout.LayoutParams(
            LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT
        ).apply { topMargin = 16 }
        setOnClickListener {
            progress = 0
            progressBar.progress = 0
            progressText.text = getString(R.string.progress_initial)

            handler.post(object : Runnable {
                override fun run() {
                    if (progress < 100) {
                        progress += 10
                        progressBar.progress = progress
                        progressText.text = "Progress: $progress%"
                        handler.postDelayed(this, 1000)
                    }
                }
            })
        }
    }

    // 组装布局
    layout.addView(label)
    layout.addView(progressBar)
    layout.addView(progressText)
    layout.addView(startButton)

    // 设置布局
    setContentView(layout)
}

override fun onDestroy() {
    super.onDestroy()
    handler.removeCallbacksAndMessages(null)
}

}

3.3 使用 Jetpack Compose

Compose 提供 LinearProgressIndicator(水平进度条)和 CircularProgressIndicator(圆形进度条)替代 ProgressBar。


package com.example.myapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.*

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ProgressScreen()
}
}
}

@Composable
fun ProgressScreen() {
var progress by remember { mutableStateOf(0f) }
val coroutineScope = rememberCoroutineScope()

Column(
    modifier = Modifier
        .fillMaxSize()
        .padding(16.dp),
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Text("Download Progress", fontSize = 18.sp)
    Spacer(modifier = Modifier.height(16.dp))

    // LinearProgressIndicator
    LinearProgressIndicator(
        progress = { progress / 100f },
        modifier = Modifier
            .fillMaxWidth()
            .height(8.dp),
        color = Color(0xFF6200EE),
        trackColor = Color(0xFFCCCCCC)
    )

    // Progress Text
    Text(
        text = "Progress: ${progress.toInt()}%",
        fontSize = 16.sp,
        modifier = Modifier.padding(top = 8.dp)
    )

    // Start Button
    Button(
        onClick = {
            progress = 0f
            coroutineScope.launch {
                while (progress < 100f) {
                    progress += 10f
                    delay(1000)
                }
            }
        },
        modifier = Modifier.padding(top = 16.dp)
    ) {
        Text("Start Download")
    }
}

}

  • 依赖app/build.gradle):
    dependencies { implementation “androidx.compose.material3:material3:1.3.0” implementation “org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1” } android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion “1.5.14” } }
  • 效果
  • LinearProgressIndicator 显示进度,初始 0%。
  • 点击按钮,进度每秒增加 10%。

4. 不确定模式(圆形进度条)

以下是一个加载动画的示例,使用不确定模式的 ProgressBar。

<!-- Indeterminate ProgressBar -->
<ProgressBar
    android:id="@+id/loadingProgress"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:indeterminate="true"
    android:indeterminateTint="@color/purple_500"
    android:contentDescription="@string/loading_desc" />

<!-- Toggle Button -->
<Button
    android:id="@+id/toggleButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/toggle_loading"
    android:layout_marginTop="16dp" />
  • 资源文件res/values/strings.xml):
    Loading spinner Toggle Loading
  • ActivityLoadingActivity.kt):

    package com.example.myapp

import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity

class LoadingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_loading)

    val loadingProgress: ProgressBar = findViewById(R.id.loadingProgress)
    val toggleButton: Button = findViewById(R.id.toggleButton)

    toggleButton.setOnClickListener {
        loadingProgress.visibility = if (loadingProgress.visibility == View.VISIBLE) {
            View.GONE
        } else {
            View.VISIBLE
        }
    }
}

}

  • 效果
  • 圆形 ProgressBar 显示加载动画。
  • 按钮切换动画的显示/隐藏。

5. 自定义 ProgressBar

  • 自定义水平进度条res/drawable/custom_progress.xml):
  • 应用样式
  <ProgressBar
      android:progressDrawable="@drawable/custom_progress"
      ... />

6. 最佳实践

  • 可访问性
  • 添加 contentDescription
    xml <ProgressBar android:contentDescription="Download progress bar" ... />
  • 测试 TalkBack 功能。
  • 响应式设计
  • 使用 dp 单位。
  • 测试多屏幕适配(Android Studio 的 Layout Editor)。
  • 性能优化
  • 避免频繁更新进度(使用 Handler 或 Coroutines 控制)。
  • 检查 Overdraw(Layout Inspector)。
  • 版本控制
  • 将布局文件纳入 Git,添加 .gitignore
    /build /.idea
  • 迁移到 Compose:新项目优先使用 LinearProgressIndicator 或 CircularProgressIndicator。

7. 常见问题与解决方案

问题解决方法
进度条不更新检查 progress 设置;确保在主线程更新(使用 Handler 或 Coroutines)。
动画不显示确保 indeterminate="true";检查 indeterminateTint
样式不统一使用 progressTint 或自定义 progressDrawable;应用 Material Design。
无障碍问题添加 contentDescription;测试 TalkBack。

8. 进阶提示

  • 异步任务结合
  CoroutineScope(Dispatchers.Main).launch {
      while (progress < 100) {
          progress += 10
          downloadProgress.progress = progress
          delay(1000)
      }
  }
  • Compose 动态动画
  var progress by remember { mutableStateOf(0f) }
  LaunchedEffect(Unit) {
      while (progress < 100f) {
          progress += 10f
          delay(1000)
      }
  }
  LinearProgressIndicator(progress = { progress / 100f })
  • 自定义圆形进度条res/drawable/custom_indeterminate.xml):
  <rotate xmlns:android="http://schemas.android.com/apk/res/android"
      android:fromDegrees="0"
      android:toDegrees="360"
      android:pivotX="50%"
      android:pivotY="50%"
      android:duration="1200">
      <shape android:shape="ring" android:thicknessRatio="20">
          <solid android:color="#6200EE" />
      </shape>
  </rotate>

9. 总结

ProgressBar 是 Android 中展示任务进度的核心组件,支持水平和圆形(不确定)模式,适用于下载、加载等场景。通过 progressmaxindeterminate 属性实现灵活控制,结合自定义 Drawable 可增强视觉效果。现代开发推荐 Jetpack Compose 的 LinearProgressIndicator 和 CircularProgressIndicator,以简化开发并提升一致性。结合 Material Design 和最佳实践,可构建直观、响应式的进度界面。

如果需要更复杂示例(如自定义动画、异步任务)、特定场景指导,或其他 Android 相关问题(如其他 View 对比),请告诉我!

类似文章

发表回复

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