跳到主要内容
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
开始使用WebReactSwiftUIJetpack ComposeFlutterReact Native预设你自己的设计系统与 AI 代理一起使用 Tanrei品牌设计令牌设计系统与定制Theme Studio颜色字体排印图标形状层级动效交互状态行为布局无障碍文字颜色令牌字阶令牌形状令牌层级令牌动效令牌状态令牌间距与度量令牌组件按钮主操作按钮分段按钮按钮组带菜单的按钮工具栏复制按钮复选框单选按钮开关纸片(Chip)菜单滑块滑块字段日历DateTimePicker字段组单选组复选框组下拉选择框下拉选择字段菜单栏文件上传文件选择器 进阶放置区文本输入框 进阶文本字段纸片字段字段组合框 进阶组合框字段数字输入框 进阶数字字段颜色输入框 进阶颜色字段一次性验证码输入框 进阶一次性验证码字段嵌入式文本输入框 进阶聊天输入栏卡片分隔线模态层 进阶对话框列表列表行底部面板侧边面板轮播代码块表格弹出框步骤折叠面板描述列表图示应用外壳页头树视图时间线图片预览调整手柄可调整大小的框滚动区域徽标进度指示器计量条数字滚动器加载指示器消息条(Snackbar)工具提示键盘快捷键标签(Tag)行内代码提示块(Callout)头像空状态标签组(Tag group)骨架屏文件项色块跑马灯文本标签页标签页视图应用栏导航栏导航抽屉搜索链接分页上一页/下一页链接步骤条面包屑目录链接卡片FAB 菜单状态Tanrei 是如何构建的参与贡献许可与致谢
首页组件加载指示器

加载指示器

表示一段时长未知的短暂等待正在进行,可以内嵌在内容里,也可以浮在内容之上。

content_copy以 Markdown 格式查看
类别
信息传达
令牌
comp.loading-indicator
层级
基础

概览

Web
tanrei-loading-indicator
schedule
SwiftUI
TanreiLoadingIndicator
schedule
Jetpack Compose
TanreiLoadingIndicator
schedule
Flutter
TanreiLoadingIndicator
schedule
React Native
LoadingIndicator
schedule

生成自 docs/status/status.json, specs/loading-indicator.spec.json

规格已修订,尚未覆盖所有平台

本页描述的是规格当前所定的加载指示器:它先等待一段时间再显示,然后以入场效果出现。Web 组件已经如此,本页的演示也是这样,它们会在延迟之后出现。SwiftUI、Compose、Flutter 和 React Native 在上方标记为“待跟进”:在跟上之前,它们一插入就绘制指示器并把它提供给辅助技术,也不接受三个新属性,所以下面这些平台的示例只展示它们实际提供的内容。

内嵌和带容器

用法

<section aria-busy="true">
  <tanrei-loading-indicator label="正在加载消息"></tanrei-loading-indicator>
</section>

<!-- 带容器:画在它自己的抬升的圆形上,浮在内容之上。 -->
<tanrei-loading-indicator contained size="large" label="正在刷新"></tanrei-loading-indicator>

<!-- 忙碌的按钮要立即回应按下:没有延迟。 -->
<tanrei-loading-indicator size="small" show-delay="0" label="正在保存"></tanrei-loading-indicator>

<!-- 给某一个指示器另一种节奏:等得更久,然后放大入场。 -->
<tanrei-loading-indicator show-delay="600" entrance="grow" label="正在加载报告"></tanrei-loading-indicator>

<script type="module">
  import '@tanrei/web/components/loading-indicator';
</script>
import { LoadingIndicator } from '@tanrei/react';

<section aria-busy={loading}>
  {loading ? <LoadingIndicator label="正在加载消息" /> : <MessageList />}
</section>
<LoadingIndicator contained size="large" label="正在刷新" />
<LoadingIndicator size="small" showDelay={0} label="正在保存" />
<LoadingIndicator showDelay={600} entrance="grow" label="正在加载报告" />
import Tanrei

TanreiLoadingIndicator("正在加载消息")

// 浮在内容之上,带它自己的抬升容器。
TanreiLoadingIndicator("正在刷新", size: .large, contained: true)
import io.github.chnotchy.tanrei.components.TanreiContainedLoadingIndicator
import io.github.chnotchy.tanrei.components.TanreiLoadingIndicator
import io.github.chnotchy.tanrei.tokens.TanreiLoadingIndicatorSize

TanreiLoadingIndicator(contentDescription = "正在加载消息")

// 带容器的形式是另一个可组合函数,参数相同。
TanreiContainedLoadingIndicator(contentDescription = "正在刷新", size = TanreiLoadingIndicatorSize.Large)
import 'package:tanrei/tanrei.dart';

const TanreiLoadingIndicator(semanticsLabel: '正在加载消息');
const TanreiLoadingIndicator(
  semanticsLabel: '正在刷新',
  size: TanreiLoadingIndicatorSize.large,
  contained: true,
);
import { LoadingIndicator } from '@tanrei/react-native';

<LoadingIndicator accessibilityLabel="正在加载消息" />
<LoadingIndicator accessibilityLabel="正在刷新" size="large" contained />

规格

各种尺寸,内嵌和带容器

构成

构成

绘制在 Web 包所绘的测试样例 small 之上。
部件 说明
1 indicator The moving mark: an arc a quarter of a circle long that turns. It has no track, because there is no value to read.
2 container · 可选 A filled, raised circle behind the indicator, drawn only when contained, so the indicator can be seen over content.

尺寸

尺寸

长度 令牌 值(px)
indicator size tanrei.comp.loading-indicator.indicator.size.small 16
绘制在 Web 包所绘的测试样例 small 之上。

属性

属性 类型 默认值 说明
size small | medium | large "medium" The indicator's box (16 / 24 / 40): small replaces an icon in a control, medium sits next to text, large fills an empty section. Contained, the container is 24 / 32 / 48. A design system may add values.
contained boolean false Draws the indicator on a raised container of its own, for places where it floats over content (pull to refresh, over an image or a list).
label string "" The accessible name: what is loading ("Loading messages"). Required: a moving mark alone is not a name.
showDelay number null How long, in milliseconds, this indicator waits from the moment it is inserted before it is drawn and exposed to assistive technology; 0 shows it as it is inserted. Null takes comp.loading-indicator.motion.show-delay, the system's answer for every indicator. Set it only where one indicator needs another pace than the rest (a wait the product knows is never instant, a busy button that should answer the press at once).
entrance auto | fade | grow "auto" How this indicator enters once its show delay has passed: fade eases it in, grow eases it in while it grows from its center. Auto takes comp.loading-indicator.motion.entrance, the system's answer for every indicator. Under reduced motion grow enters as fade (LDG-13).
enterDuration number null How long, in milliseconds, this indicator's entrance lasts; 0 shows it whole at once. Null takes comp.loading-indicator.motion.enter-duration.

状态

行为

以 EARS 形式写成的需求。每个平台的实现都按这些 ID 逐条测试。需求原文取自规格文件,原样以英文呈现。

ID 需求
LDG-1 THE loading indicator SHALL draw, inside a comp.loading-indicator.indicator.size.medium square for medium (and so on for each size), an arc a quarter of the circle long with round caps and a stroke of comp.loading-indicator.indicator.thickness.medium for medium (and so on), whose outer edge touches the square, and SHALL turn it clockwise once per comp.loading-indicator.motion.cycle-duration at constant speed (sys.motion.easing.linear); it SHALL draw no track.
LDG-2 WHILE contained is false THE loading indicator SHALL take exactly its indicator square, draw no container, and draw the arc in comp.loading-indicator.indicator.color.
LDG-3 WHILE contained is true THE loading indicator SHALL draw a container of comp.loading-indicator.container.size.medium for medium (and so on for each size) with corners of comp.loading-indicator.container.shape, filled with comp.loading-indicator.contained.container.color and raised by comp.loading-indicator.contained.container.elevation, center the indicator in it, and draw the arc in comp.loading-indicator.contained.indicator.color.
LDG-4 WHERE reduced motion is requested THE loading indicator SHALL NOT turn: it SHALL draw the whole circle at the indicator's size and stroke and ease its opacity from 1 to 0 and back to 1 once per comp.loading-indicator.motion.cycle-duration with sys.motion.easing.standard; a container, when contained, SHALL stay still and opaque.
LDG-5 WHILE the loading indicator is shown (LDG-12) THE loading indicator SHALL expose the progressbar role to assistive technology with label as its name, no current value, and the platform's busy or indeterminate state.
LDG-6 THE loading indicator SHALL NOT be focusable and SHALL NOT announce itself when it appears or disappears; the region being loaded is marked busy, and its completion announced, by the product.
LDG-7 WHILE the loading indicator is not visible (scrolled out of view, in a hidden view, or in an app in the background) THE loading indicator SHALL NOT run its animation, and SHALL resume it when it becomes visible.
LDG-8 WHERE the layout direction is right-to-left THE loading indicator SHALL NOT be mirrored: it turns clockwise in every direction.
LDG-9 WHEN size names a value that the active design system does not have THE loading indicator SHALL render with the default value's tokens, and in debug builds report the unknown value.
LDG-10 WHILE label is empty THE loading indicator SHALL still render, and in debug builds report that it has no accessible name.
LDG-11 WHEN the loading indicator is inserted into a view THE loading indicator SHALL wait for its show delay (LDG-14) before it is shown, and WHILE it waits SHALL draw nothing (no indicator, no container, no shadow), SHALL run no animation, SHALL be absent from the accessibility tree (no role, no name, no busy state), and SHALL still take the box it takes when shown (LDG-2, LDG-3), so that nothing around it moves when it appears; a show delay of 0 SHALL show it as it is inserted.
LDG-12 WHEN its show delay ends THE loading indicator SHALL be shown: it SHALL expose itself as LDG-5 says, without announcing itself (LDG-6), start its entrance (LDG-13), and start the turn of LDG-1, or the pulse of LDG-4, at the beginning of a cycle.
LDG-13 WHEN the loading indicator is shown THE loading indicator SHALL enter over its enter duration (LDG-14) with comp.loading-indicator.motion.enter-easing, as its entrance names: fade SHALL ease the opacity of the whole component (the indicator and, when contained, the container and its shadow) from 0 to 1, and grow SHALL ease the opacity the same way while scaling the whole component from nothing to its full size about its center, on the same curve over the same time. The entrance SHALL be drawn only: the box SHALL keep its full size throughout, and the entrance SHALL run to its end whether or not the indicator is visible (LDG-7 pauses the cycle, not the entrance). An enter duration of 0 SHALL show the indicator whole at once. WHERE reduced motion is requested THE loading indicator SHALL NOT scale: grow SHALL enter as fade, and on a platform whose reduced-motion setting removes every animation (Android's) the indicator SHALL appear at once.
LDG-14 THE loading indicator SHALL take its show delay from showDelay and its enter duration from enterDuration, each a number of milliseconds used as given (the motion dial does not scale it), and its kind of entrance from entrance. WHILE showDelay or enterDuration is null THE loading indicator SHALL use comp.loading-indicator.motion.show-delay or comp.loading-indicator.motion.enter-duration in its place, and WHILE entrance is auto it SHALL use comp.loading-indicator.motion.entrance; IF showDelay or enterDuration is negative or not a finite number, or entrance names a kind the indicator does not know, THE loading indicator SHALL use the token likewise and in debug builds report the value it ignored.
LDG-15 THE loading indicator SHALL treat its show delay as a waiting time, not motion: WHERE motion is reduced it SHALL keep it, on every platform, including one whose reduced-motion setting removes every animation; and it SHALL keep counting it while the indicator cannot be seen (scrolled out of view, in a hidden view), because the delay measures the wait, not what is seen.
LDG-16 WHEN the loading indicator is removed before its show delay ends THE loading indicator SHALL have drawn, exposed and announced nothing, and WHEN it is removed while shown, during its entrance included, it SHALL disappear at once. WHEN it is inserted again THE loading indicator SHALL wait its whole show delay again; hiding it without removing it (a hidden ancestor, scrolling) SHALL neither restart nor pause the delay (LDG-15). WHEN showDelay, entrance or enterDuration changes while the delay or the entrance is running THE loading indicator SHALL finish the running one as it started and use the new value from its next insertion.
LDG-17 THE loading indicator SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the loading indicator is shown THE loading indicator SHALL draw itself for the new direction at once, without a motion of its own, keeping its place in its cycle.
LDG-18 WHERE the platform has ARIA attributes (the web), the host carries its progressbar role (LDG-5) itself, so what the product writes on it is not moved, but for a name: WHILE label is not empty THE loading indicator SHALL hold the product's aria-label and aria-labelledby on that host as their data-aria- twins, so that label is its whole name although the platform gives aria-labelledby the precedence, and WHEN label is emptied SHALL give them back as they were written; WHILE label is empty a name the product gives so — aria-label, or aria-labelledby naming an element — SHALL be its name and SHALL NOT be reported as having none in debug builds (LDG-10). WHILE it waits to be shown (LDG-11) it has no role, and SHALL hold them as well, so that nothing names an element with no role, and give them back when it is shown. WHEN the product removes one, or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaLabelledByElements) to null, THE loading indicator SHALL take it away.

各平台名称对照

对等并不意味着 API 完全相同。同一份契约,由各平台以自己的惯用方式表达。

规格 Web SwiftUI Jetpack Compose Flutter React Native
组件 tanrei-loading-indicator TanreiLoadingIndicator TanreiLoadingIndicator TanreiLoadingIndicator LoadingIndicator
size · 属性 size size size size size
contained · 属性 contained contained TanreiContainedLoadingIndicator contained contained
label · 属性 label label contentDescription semanticsLabel accessibilityLabel
showDelay · 属性 showDelay showDelay showDelayMillis showDelay showDelay
entrance · 属性 entrance entrance entrance entrance entrance
enterDuration · 属性 enterDuration enterDuration enterDurationMillis enterDuration enterDuration
备注 The host carries role="progressbar", aria-label and aria-busy="true" once shown, and no aria-value attributes; during the show delay it carries none of them and is aria-hidden="true", and its parts are visibility: hidden while the host keeps its size (LDG-11). The delay starts in connectedCallback and is cancelled in disconnectedCallback, so moving the element within the document starts a new delay; hiding it with hidden or CSS does not (LDG-16) — insert and remove it with the wait. showDelay and enterDuration are number properties in milliseconds, null by default, set by the show-delay and enter-duration attributes; an attribute that is empty or does not parse as a finite number is not a number (LDG-14), so show-delay="" takes the token and does not show at once. entrance is a string property and attribute, auto by default; auto reads --tanrei-comp-loading-indicator-motion-entrance from the cascade, which carries the choice's name. The arc turns with a CSS animation that @media (prefers-reduced-motion: reduce) replaces, and pauses while the element is not intersecting the viewport. Snapshot harness: each fixture is rendered with show-delay="0" and enter-duration="0" (LDG-11). Lagging: ships the earlier spec, drawn and exposed as it is inserted, with no delay or entrance; owes LDG-5's revision and LDG-11 to LDG-16. The target: TanreiLoadingIndicator(_ label:, size:, contained:, showDelay: Duration? = nil, entrance: TanreiLoadingEntrance? = nil, enterDuration: Duration? = nil); a Duration carries its own unit (.milliseconds(300)), nil takes the token (nil is also entrance's auto), and a negative one takes the token and is reported in debug builds. The delay is a .task bound to the view's identity (cancelled when the view leaves the hierarchy), and the view is .accessibilityHidden(true) and at zero opacity until it ends, keeping its frame. Reduced motion is accessibilityReduceMotion from the environment. Snapshot harness: renders each fixture with showDelay: .zero and enterDuration: .zero. Lagging: ships the earlier spec, drawn and exposed as it is inserted, with no delay or entrance; owes LDG-5's revision and LDG-11 to LDG-16. The target adds showDelayMillis: Long? = null, entrance: TanreiLoadingEntrance? = null (null is auto) and enterDurationMillis: Long? = null to both composables, named in milliseconds as ViewConfiguration.longPressTimeoutMillis is; null takes the token, a negative value takes the token and is reported in debug builds. The delay is a coroutine delay in a LaunchedEffect started when the indicator enters the composition, not an animation, so the animator duration scale of 0 (Android's reduced motion) does not remove it (LDG-15); until it ends the layout keeps its size, draws nothing, and its semantics are cleared. Compose idiom, as Material's LoadingIndicator and ContainedLoadingIndicator: contained is a second composable, TanreiContainedLoadingIndicator, with the same parameters, not a flag. Snapshot harness: renders each fixture with showDelayMillis = 0 and enterDurationMillis = 0. Lagging: ships the earlier spec, drawn and exposed as it is inserted, with no delay or entrance; owes LDG-5's revision and LDG-11 to LDG-16. The target adds showDelay, entrance (a TanreiLoadingEntrance?, null is auto) and enterDuration, the times as Duration?: null takes the token, a negative one takes the token and is reported in debug builds. The delay is a Timer started in initState and cancelled in dispose; until it ends the child keeps its size, paints nothing and is wrapped in ExcludeSemantics. semanticsLabel as Flutter's progress indicators name it. Reduced motion is MediaQuery.disableAnimationsOf(context); the turning animation stops with TickerMode, which covers hidden routes, and the timer does not. Snapshot harness: a golden of each fixture with showDelay: Duration.zero and enterDuration: Duration.zero. Lagging: ships the earlier spec, drawn and exposed as it is inserted, with no delay or entrance; owes LDG-5's revision and LDG-11 to LDG-16. The target: showDelay and enterDuration are numbers of milliseconds, as Pressable's delayLongPress is; undefined or null takes the token, and a negative or non-finite number takes the token and is reported in development builds; entrance is 'auto' | 'fade' | 'grow', 'auto' by default. The delay is a timer set when the component mounts and cleared when it unmounts; until it ends the view keeps its size at zero opacity with accessibilityElementsHidden and importantForAccessibility="no-hide-descendants", and once shown it takes accessibilityRole="progressbar" with accessibilityState={{ busy: true }}. Reduced motion from AccessibilityInfo.isReduceMotionEnabled(). Not React Native's ActivityIndicator, which draws the platform's own spinner and cannot follow the tokens. Snapshot harness: renders each fixture with showDelay={0} and enterDuration={0}.

令牌

令牌 引用 解析值(浅色)
--tanrei-comp-loading-indicator-contained-container-color sys.color.surface-container-lowest #ffffff
--tanrei-comp-loading-indicator-contained-container-elevation sys.elevation.level2 0px 0px 0px 1px rgb(0 0 0 / 0.08), 0px 1px 2px 0px rgb(0 0 0 / 0.04)
--tanrei-comp-loading-indicator-contained-indicator-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-loading-indicator-container-shape sys.shape.corner.full 9999px
--tanrei-comp-loading-indicator-container-size-large — 48px
--tanrei-comp-loading-indicator-container-size-medium — 32px
--tanrei-comp-loading-indicator-container-size-small — 24px
--tanrei-comp-loading-indicator-indicator-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-loading-indicator-indicator-size-large — 40px
--tanrei-comp-loading-indicator-indicator-size-medium — 24px
--tanrei-comp-loading-indicator-indicator-size-small — 16px
--tanrei-comp-loading-indicator-indicator-thickness-large sys.border.thick 2px
--tanrei-comp-loading-indicator-indicator-thickness-medium sys.border.thick 2px
--tanrei-comp-loading-indicator-indicator-thickness-small sys.border.thick 2px
--tanrei-comp-loading-indicator-motion-cycle-duration sys.motion.duration.extra-long4 1000ms
--tanrei-comp-loading-indicator-motion-enter-duration sys.motion.role.state.large 250ms
--tanrei-comp-loading-indicator-motion-enter-easing sys.motion.easing.enter cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-loading-indicator-motion-entrance — 0
--tanrei-comp-loading-indicator-motion-show-delay sys.motion.role.show-delay 300ms

测试样例

作为基准的渲染结果。所有平台都以相同的 ID 为每个样例截取快照,以便相互比较。

生成自 specs/loading-indicator.spec.json, tokens/comp/loading-indicator.tokens.json, design/tokens/

指南

何时使用

加载指示器用于你无法判断时长的短暂等待:列表正在获取下一页、控件正在保存、预览正在渲染。它说明有事情正在进行,但不说明要花多久。

如果等待可能持续几秒以上,或者你能够测量它已经进行到哪里,请改用进度指示器。一个数值,哪怕是粗略的,也会让漫长的等待更容易忍受。

如何选择尺寸

尺寸 默认系统中的指示器 / 容器 用途
Small 16 / 24 在控件里代替图标,例如正在保存的按钮。
Medium 24 / 32 放在一行文本旁边。这是默认尺寸。
Large 40 / 48 等待内容的空白区域或整个视图。

带容器

带容器的形式把指示器画在它自己的抬升的圆形上。指示器浮在内容之上时使用它,例如下拉刷新时,或者位于图片或列表之上时,这样无论背后是什么,它都看得见。指示器位于素净的表面上时,保持内嵌即可。

显示延迟和入场

转眼就结束的等待不应该显示任何东西。所以指示器先等待再显示:在默认系统中是 300 毫秒,从它被插入的那一刻算起。然后它淡入。比这段延迟更短的等待,永远不会显示一个一闪而过的标记。在延迟期间,指示器已经占据它的完整尺寸,所以它出现时,旁边的任何东西都不会移动。

在等待开始时插入指示器,在等待结束时移除它。延迟从插入时算起:只是被隐藏后再次显示、没有被移除的指示器不会再等一次;重新插入的指示器会再等完整的一段延迟。

延迟和入场效果由系统为所有指示器统一决定。只有在某一个指示器需要不同的节奏时,才在它上面单独设置:

  • showDelay 是以毫秒为单位的等待时间。0 表示指示器一插入就显示,适合应当立即回应按下的忙碌按钮。
  • entrance 是 fade 或 grow。grow 让指示器在淡入的同时从中心放大。默认值 auto 采用系统的选择。
  • enterDuration 是以毫秒为单位的入场时长。0 表示指示器立即完整显示。

你设置的值会原样使用:动效调节量不会缩放它。不设置某个属性,就采用系统的值。

推荐

  • 给它一个说明正在加载什么的标签:写“正在加载消息”,不写“正在加载”。如果它旁边显示了说明文字,请使用同样的措辞。
  • 把它放在内容将要出现的位置,这样内容到达时,用户看的正是那个地方。
  • 用它代替控件里的图标时,保持控件的尺寸不变,这样周围的任何东西都不会移动。
  • 除非某个指示器需要另一种节奏,否则把延迟交给系统决定。

避免

  • 不要把它用于可以测量的等待,或可能持续很久的等待。请使用进度指示器。
  • 不要为同一次等待显示多个指示器。每个正在加载的区域一个就够了。
  • 屏幕上只有一部分在加载时,不要让它盖住整个屏幕。让其余部分保持可用。
  • 不要用给它着色的方式表示出了问题。应当停止指示器,并显示一条消息。
  • 不要把指示器一直留在原处,只在两次等待之间把它隐藏。要移除它,这样下一次等待才会开始新的延迟。

无障碍

角色
progressbar
标注
label is the accessible name. The indicator has no value: once shown, it is exposed as a progressbar in the platform's busy (indeterminate) state, never as a status message; during its show delay it is not exposed at all (LDG-11).
最小目标
即使外观尺寸更小,点击区域也满足最小目标尺寸。 minimum 32px · pointer 44px · spacing 8px · touch 48px

键盘操作

按键 动作

备注

  • Not interactive: the indicator takes no input and is never focusable (LDG-6), so the minimum target holds without extending anything.
  • comp.loading-indicator.indicator.color must stay at least 3:1 against the surface behind it, and comp.loading-indicator.contained.indicator.color against comp.loading-indicator.contained.container.color (non-text contrast): the moving mark is the only sign that something is happening.
  • Text size does not change the indicator: it is not text. Where it replaces an icon in a control, the control keeps its size.
  • A product marks the region it loads as busy (aria-busy on the web) and says when the content has arrived; a wait that may exceed a few seconds, or whose length can be measured, belongs to the progress indicator.
  • A wait shorter than the show delay shows and exposes nothing (LDG-11): no mark that flashes for a sighted person, and no progressbar that appears and vanishes for a screen-reader user. The product's own busy marking of the region does not wait for the delay; aria-busy and its equivalents announce nothing by themselves.
  • Reduced motion replaces the turning arc with an opacity pulse of at most one per second (LDG-4), below the three-per-second flash threshold, and turns a grow entrance into a fade (LDG-13). The show delay is kept: it is a wait, not motion (LDG-15).

生成自 specs/loading-indicator.spec.json, tokens/sys/measure.tokens.json

组件负责的部分

  • 显示之后,它以平台的“忙碌”状态提供进度条角色,以标签作为名称,没有数值。Flutter 目前还没有进度条角色和忙碌状态,所以在那里它只提供标签。
  • 在显示延迟期间,它完全不在无障碍树之内:没有角色,没有名称,没有忙碌状态。短到看不见的等待,同样也听不到。
  • 它从不可聚焦,出现或消失时也不会自行朗读。
  • 用户要求减弱动态效果时,圆弧停止转动,改为一个完整的圆环轻缓地改变不透明度,每秒至多一次;容器保持静止。grow 入场变为淡入。显示延迟保持不变:它是等待,不是动效。
  • 在看不见它的时候,它的动画会停止——在所有平台上,应用处于后台时都是如此;在平台能够判断的情况下,它被滚出视野或位于隐藏的屏幕上时也是如此——看得见时再恢复。
  • 空的标签会在调试构建中报告。

需要你做的事

  • 在加载期间把正在加载的区域标记为忙碌(在 Web 上是 aria-busy),从等待开始时就标记,不要等指示器的延迟结束;并在内容到达时告知用户:在实时区域(live region)里放一条消息,或者在内容是用户主动请求的情况下,把焦点移到新内容上。
  • 如果你更改了颜色,请让指示器的颜色相对于它背后的表面至少保持 3:1 的对比度,带容器的指示器的颜色相对于它的容器也是如此。这个运动的标记是表明有事情正在进行的唯一信号。