跳到正文

进度指示器 ​

LoaderKitProgress 用来显示任务完成了多少。它有 10 种 type、50 种样式,每种样式都可以显示具体的 value,也可以在 value 未知时以不确定状态运行。value 变化时,指示器会平滑过渡到新的 value。点击任意一种样式即可打开面板:调整 value、粗细、尺寸和颜色,然后复制对应平台的代码。

内置加载动画还是进度指示器?

  • 始终没有百分比(等待请求、下拉刷新):用内置加载动画,有 50 种样式可选。
  • 任务有进度,哪怕一开始还不知道(下载、上传、处理文件):用本页的进度指示器。先以不确定状态开始(value 为 null,Swift 中为 nil),知道进度后再设置 value。始终是同一个组件,其他代码都不用改。
0.40

进度指示器不使用 JSON spec。每种 type 在所有平台上都由同一套几何逻辑绘制:一份参考实现把选项和动画状态转换成绘制命令,每个平台的移植版本都运行同一套测试向量。因此同一种样式在 Web、Android、iOS、macOS 和 Windows 上的外观和动效都一致。

快速开始 ​

html
<script type="module">
  import '@loader-kit/web/progress-element';
</script>

<!-- 不确定状态的 circular,48 × 48 -->
<loader-kit-progress></loader-kit-progress>

<loader-kit-progress type="linear" value="0.4"></loader-kit-progress>
<loader-kit-progress type="gauge" value="0.7" show-label size="64"></loader-kit-progress>
tsx
import { LoaderKitProgress } from '@loader-kit/web/react';

<LoaderKitProgress type="linear" value={progress} />
<LoaderKitProgress value={done ? 1 : null} />
vue
<script setup lang="ts">
import { LoaderKitProgress } from '@loader-kit/web/vue';
</script>

<template>
  <LoaderKitProgress type="linear" :value="progress" />
</template>
svelte
<script>
  import { LoaderKitProgress } from '@loader-kit/web/svelte';
</script>

<LoaderKitProgress type="linear" value={progress} />
xml
<io.github.maitrungduc1410.loaderkit.LoaderKitProgressView
    android:id="@+id/progress"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:progressType="linear"
    app:progressValue="0.4" />
kotlin
LoaderKitProgress(
    value = progress,
    modifier = Modifier.fillMaxWidth(),
    type = ProgressType.Linear,
)
swift
let progress = LoaderKitProgressView(value: 0.4, type: .linear)
progress.value = 0.8   // 平滑过渡到 0.8
swift
LoaderKitProgress(value: progress, type: .linear)
xml
<lk:LoaderKitProgress Type="Linear" Value="{x:Bind ViewModel.Progress, Mode=OneWay}" />

Value ​

value 的范围是 0 到 1,超出范围的值会被截断。null(Swift 中为 nil)或 NaN 会显示不确定状态的动画,所以同一个视图既能表示"还不知道进度",也能表示"已完成 40%":

ts
const view = new LoaderKitProgressView(host, { type: 'linear' });  // 不确定状态
view.value = 0.25;
view.value = null;   // 回到不确定状态
kotlin
progress.value = 0.25
progress.value = null
swift
progress.value = 0.25
progress.value = nil
csharp
progress.Value = 0.25;
progress.Value = null;

buffer 会在 linear flat 和 wavy 的 value 前方再画一条颜色更浅的进度条,类似视频已缓冲的部分。

平滑过渡 ​

smooth 默认开启。新的 value 不会直接跳过去,而是平滑过渡,百分比标签也会跟着计数。过渡的节奏会跟随更新的频率:

  • 连续密集的更新(比如下载文件时不断到达的数据)会匀速前进,而不是每次更新都停一下。
  • 单独的一次更新用时半秒,结尾逐渐减速。
  • 向回走(比如回到 0)用时 0.4 秒。
  • 绘制出的 value 永远不会超过真实 value,在 value 增长时也不会向回走。

屏幕阅读器读取的始终是真实 value,而不是正在绘制的 value。关闭 smooth 后,每个 value 都会立即绘制:

html
<loader-kit-progress type="linear" value="0.4" smooth="false"></loader-kit-progress>
tsx
<LoaderKitProgress type="linear" value={progress} smooth={false} />
kotlin
LoaderKitProgress(value = progress, type = ProgressType.Linear, smooth = false)
swift
LoaderKitProgress(value: progress, type: .linear).smooth(false)
xml
<lk:LoaderKitProgress Type="Linear" Value="{x:Bind ViewModel.Progress, Mode=OneWay}" Smooth="False" />

Type 与 variant ​

type 决定形状,variant 决定风格。如果某个 type 没有指定的 variant,会回退到它列表中的第一个 variant。

TypeVariant布局不限制尺寸时的大小
linearflat、wavy、segmented、striped、shimmer、glow、dots、steps、gradient、center、chevrons、ticks宽度占满;高度取决于 thickness
circular(默认)flat、wavy、segmented、gradient、ticks、dots、glow、split、orbit、dualsize × size
pieflat、segmentedsize × size
gaugeflat、segmented、needle、gradient、dotssize × size
liquidflat、heartsize × size
borderflat、glow、segmented包裹内容
barsflat、dots、arcssize × 0.75 size
gridflat、dotssize × size
batteryflat、segmentedsize × 0.5 size
hourglassflatsize × size

size 是像素数(Android 上是 dp,Apple 上是 point),默认是 48;与 LoaderKit 不同,它不接受 CSS 长度。小于 32 时,circular wavy 会画成平的,因为这么小的尺寸下波浪已经看不清。hourglass 没有显示百分比的空间,所以会忽略 showLabel。

有些样式即使 value 不变也会动:wavy 和 liquid 的波浪、striped 的条纹和 shimmer 的光泽。

选项 ​

选项默认值作用
thickness取决于 type 和 variant线条和进度条的粗细
trackGap4进度与 track 之间、或各段之间的间距
segments取决于 type 和 variant段、点、刻度、步骤、柱子的数量,或 grid 的列数
showLabelfalse在指示器内部或旁边显示百分比
stopIndicatortruelinear flat 和 wavy 的 track 末端的圆点
strokeCapround线条端点:round 或 butt
amplitude、wavelength、waveSpeedlinear 为 3、40、1;circular 为 2、15、1wavy 的波浪
sweepAngle270gauge 的弧度,单位为度,范围 30 到 350
cornerRadius12border 的圆角
speed1不确定状态动画的播放速度;0 或更小会暂停
color强调色;Web 上为 CSS color进度部分
trackColorcolor 的 24% 不透明度track
labelColor文字颜色;Web 上为 CSS color百分比标签
respectsReduceMotiontrue见减弱动态效果

长度单位在 Web 上是 CSS px,在 Android 上是 dp,在 Apple 平台上是 point,在 Windows 上是有效像素。

各平台的名称 ​

概念<loader-kit-progress>React、Vue、Svelte、Android、Compose、SwiftWindows
ValuevaluevalueValue
平滑过渡smoothsmoothSmooth
选项track-gap、show-label、stop-indicator、stroke-cap、wave-speed、sweep-angle、corner-radiustrackGap、showLabel、stopIndicator、strokeCap、waveSpeed、sweepAngle、cornerRadiusTrackGap、ShowLabel、StopIndicator、StrokeCap、WaveSpeed、SweepAngle、ProgressCornerRadius
颜色color、track-color、label-colorcolor、trackColor、labelColorColor、TrackColor、LabelColor

在 SwiftUI 中,每个选项都是一个 modifier(.thickness(6)、.showLabel())。在 Android XML 中,每个选项都是 app:progress 加上它的名称(app:progressType、app:progressValue、app:progressShowLabel、app:progressSweepAngle、app:progressRespectsReduceMotion 等),只有速度是 app:speed,与 LoaderKitView 相同。在 Windows 上,每个控件都已经有 CornerRadius 属性,所以这个选项叫 ProgressCornerRadius。

内容 ​

进度指示器可以包含内容:放在 circular、pie、gauge 等方形 type 的中间,或者放在 border 的描边内部,此时边框会扩展以包裹内容。

html
<loader-kit-progress value="0.3">
  <button aria-label="Stop">■</button>
</loader-kit-progress>

<loader-kit-progress type="border">
  <button>Upload</button>
</loader-kit-progress>
kotlin
LoaderKitProgress(value = progress) {
    IconButton(onClick = cancel) { Icon(Icons.Filled.Stop, contentDescription = "Stop") }
}
swift
LoaderKitProgress(value: progress, type: .border) {
    Button("Upload", action: upload)
}
xml
<lk:LoaderKitProgress Type="Border">
    <Button Content="Upload" Click="OnUpload" />
</lk:LoaderKitProgress>

Android 视图是一个 ViewGroup:在 XML 中或用 addView 添加子视图。在 UIKit 和 AppKit 中,把要显示的视图赋给 contentView,例如 progress.contentView = stopButton。

无障碍 ​

所有平台都把指示器作为进度条暴露给辅助技术,value 以 0 到 100 的百分比表示,不确定状态下没有 value。在 Web、Apple 平台和 Windows 上,默认的无障碍名称是 "Loading";Android 会读出进度条和百分比。请说明正在加载的内容:使用 aria-label(React、Vue 和 Svelte 组件中为 accessibilityLabel)、Android 和 Compose 上的 contentDescription、Apple 平台上的 accessibilityLabel,或 Windows 上的 AutomationProperties.Name。

减弱动态效果 ​

当系统要求减弱动态效果时,value 会直接跳到新值而不是平滑过渡,波浪、条纹和光泽会停止,不确定状态的动画以一半速度运行,让用户仍能看出任务正在进行。各平台的系统设置见播放控制。把 respectsReduceMotion 设为 false 可以保留完整的动效。

基于 MIT 许可证发布。