Skip to content

Commit 9f61b03

Browse files
authored
Merge branch 'main' into sync-20240902
2 parents aa8584d + 7aefa2f commit 9f61b03

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

src/content/cookbook/effects/shimmer-loading.md

+146
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,56 @@ to communicate to users that data is loading is to
1818
display a chrome color with a shimmer animation over
1919
the shapes that approximate the type of content that is loading.
2020

21+
在应用开发中,加载时间是不可避免的。
22+
从用户体验 (UX) 的角度来看,
23+
最重要的是向用户展示正在进行加载操作。
24+
一种常见的方式是,
25+
在近似加载内容形状的区域上,
26+
显示带有微光动画的镀铬颜色覆盖层,
27+
以此来告知用户数据正在加载。
28+
2129
The following animation shows the app's behavior:
2230

31+
下面的动画展示了应用程序的行为:
32+
2333
![Gif showing the UI loading](/assets/images/docs/cookbook/effects/UILoadingAnimation.gif){:.site-mobile-screenshot}
2434

2535
This recipe begins with the content widgets defined and positioned.
2636
There is also a Floating Action Button (FAB) in the bottom-right
2737
corner that toggles between a loading mode and a loaded mode
2838
so that you can easily validate your implementation.
2939

40+
该示例从准备好的内容 widget 开始。
41+
界面右下角还放置了一个浮动操作按钮 (FAB),
42+
用于切换正在加载和已加载的模式,
43+
以便你可以轻松验证实现的效果。
44+
3045
## Draw the shimmer shapes
3146

47+
## 绘制微光效果的形状
48+
3249
The shapes that shimmer in this effect are independent
3350
from the actual content that eventually loads.
3451

52+
在这个效果中,微光的形状是独立于最终加载的实际内容的。
53+
3554
Therefore, the goal is to display shapes that represent
3655
the eventual content as accurately as possible.
3756

57+
因此,目标是尽可能准确地显示代表最终内容的形状。
58+
3859
Displaying accurate shapes is easy in situations where the
3960
content has a clear boundary. For example, in this recipe,
4061
there are some circular images and some rounded rectangle images.
4162
You can draw shapes that precisely match the outlines
4263
of those images.
4364

65+
在内容有明确边界的情况下,
66+
显示准确的形状很容易。
67+
例如,在这个示例中,
68+
有一些圆形图片和一些圆角矩形图片。
69+
你可以绘制与这些图片轮廓完全匹配的形状。
70+
4471
On the other hand, consider the text that appears beneath the
4572
rounded rectangle images. You won't know how many lines of
4673
text exist until the text loads.
@@ -50,10 +77,21 @@ you draw a couple of very thin rounded rectangles that
5077
represent the text that will appear. The shape and size
5178
doesn't quite match, but that is OK.
5279

80+
另一方面,考虑显示在圆角矩形图片下方的文本。
81+
在文本加载之前,你不会知道有多少行文本。
82+
因此,尝试为每行文本绘制一个矩形是没有意义的。
83+
相反,当数据加载时,
84+
你可以绘制几个非常细的圆角矩形来代表即将出现的文本。
85+
形状和大小可能不完全匹配,
86+
但这样做是可以的。
87+
5388
Start with the circular list items at the top of the screen.
5489
Ensure that each `CircleListItem` widget displays a circle
5590
with a color while the image is loading.
5691

92+
从屏幕顶部的圆形列表项开始。
93+
确保每个 `CircleListItem` widget 在图片加载时显示一个有颜色的圆形。
94+
5795
<?code-excerpt "lib/main.dart (CircleListItem)"?>
5896
```dart
5997
class CircleListItem extends StatelessWidget {
@@ -86,13 +124,21 @@ class CircleListItem extends StatelessWidget {
86124
As long as your widgets display some kind of shape,
87125
you can apply the shimmer effect in this recipe.
88126

127+
只要你的 widget 显示某种形状,
128+
你就可以在这个示例中应用微光效果。
129+
89130
Similar to the `CircleListItem` widgets,
90131
ensure that the `CardListItem` widgets
91132
display a color where the image will appear.
92133
Also, in the `CardListItem` widget,
93134
switch between the display of the text and
94135
the rectangles based on the current loading status.
95136

137+
类似于 `CircleListItem` widget,
138+
确保 `CardListItem` widget 在图片将出现的地方显示颜色。
139+
同时,在 `CardListItem` widget 中,
140+
根据当前的加载状态在文本和矩形的显示之间切换。
141+
96142
<?code-excerpt "lib/main.dart (CardListItem)"?>
97143
```dart
98144
class CardListItem extends StatelessWidget {
@@ -181,24 +227,40 @@ whether it's loading or loaded.
181227
By temporarily commenting out the image URLs,
182228
you can see the two ways your UI renders.
183229

230+
现在,你的 UI 会根据是否正在加载或已加载来呈现不同的效果。
231+
通过暂时注释掉图像 URL,
232+
你可以看到 UI 呈现的两种方式。
233+
184234

185235
![Gif showing the shimmer animation](/assets/images/docs/cookbook/effects/LoadingShimmer.gif){:.site-mobile-screenshot}
186236

187237
The next goal is to paint all of the colored areas
188238
with a single gradient that looks like a shimmer.
189239

240+
接下来的目标是将所有着色区域涂上一层看起来像微光效果的渐变。
241+
190242
## Paint the shimmer gradient
191243

244+
## 绘制微光渐变效果
245+
192246
The key to the effect achieved in this recipe is to use a widget
193247
called [`ShaderMask`][]. The `ShaderMask` widget, as the name suggests,
194248
applies a shader to its child, but only in the areas where
195249
the child already painted something. For example,
196250
you'll apply a shader to only the black shapes that you
197251
configured earlier.
198252

253+
实现这一效果的关键是使用一个名为 [`ShaderMask`][] 的 widget。
254+
顾名思义, `ShaderMask` widget 将着色器应用于其子 widget,
255+
但仅限于子 widget 已经绘制了内容的区域。
256+
例如,你将只对之前配置的黑色形状应用着色器。
257+
199258
Define a chrome-colored, linear gradient that gets applied to the
200259
shimmer shapes.
201260

261+
定义一个铬色的线性渐变,
262+
将其应用于微光效果的形状。
263+
202264
<?code-excerpt "lib/main.dart (shimmerGradient)"?>
203265
```dart
204266
const _shimmerGradient = LinearGradient(
@@ -225,6 +287,13 @@ gradient as a shader with a `blendMode` of `srcATop`.
225287
The `srcATop` blend mode replaces any color that your
226288
`child` widget painted with the shader color.
227289

290+
定义一个新的 stateful widget,名为 `ShimmerLoading`
291+
它用 `ShaderMask` 包裹一个传入的 `child` widget。
292+
配置 `ShaderMask` widget,
293+
使微光渐变效果应用为着色器,
294+
并将 `blendMode` 设置为 `srcATop`
295+
`srcATop` 混合模式会将 `child` widget 绘制的任何颜色替换为着色器颜色。
296+
228297
<?code-excerpt "lib/main.dart (ShimmerLoading)"?>
229298
```dart
230299
class ShimmerLoading extends StatefulWidget {
@@ -261,6 +330,8 @@ class _ShimmerLoadingState extends State<ShimmerLoading> {
261330

262331
Wrap your `CircleListItem` widgets with a `ShimmerLoading` widget.
263332

333+
`ShimmerLoading` widget 包裹你的 `CircleListItem` widget。
334+
264335
<?code-excerpt "lib/shimmer_loading_items.dart (buildTopRowItem)"?>
265336
```dart
266337
Widget _buildTopRowItem() {
@@ -273,6 +344,8 @@ Widget _buildTopRowItem() {
273344

274345
Wrap your `CardListItem` widgets with a `ShimmerLoading` widget.
275346

347+
`ShimmerLoading` widget 包裹你的 `CardListItem` widget。
348+
276349
<?code-excerpt "lib/shimmer_loading_items.dart (buildListItem)"?>
277350
```dart
278351
Widget _buildListItem() {
@@ -289,6 +362,9 @@ When your shapes are loading, they now display
289362
the shimmer gradient that is
290363
returned from the `shaderCallback`.
291364

365+
当你的形状正在加载时,
366+
它们会显示从 `shaderCallback` 返回的微光渐变效果。
367+
292368
This is a big step in the right direction,
293369
but there's a problem with this gradient display.
294370
Each `CircleListItem` widget and each `CardListItem` widget
@@ -297,14 +373,27 @@ For this recipe, the entire screen should
297373
look like one, big shimmering surface.
298374
You solve this problem in the next step.
299375

376+
这是朝着正确方向迈出的重要一步,
377+
但这个渐变显示存在一个问题。
378+
每个 `CircleListItem` widget 和每个 `CardListItem` widget
379+
都会显示各自独立的渐变效果。
380+
对于这个示例,整个屏幕应该呈现为一个大而统一的微光表面。
381+
你将在下一步解决这个问题。
382+
300383
## Paint one big shimmer
301384

385+
## 绘制大而统一的微光效果
386+
302387
To paint one big shimmer across the screen,
303388
each `ShimmerLoading` widget needs
304389
to paint the same full-screen gradient based
305390
on the position of that `ShimmerLoading`
306391
widget on the screen.
307392

393+
为了在整个屏幕上绘制大而统一的微光效果,
394+
每个 `ShimmerLoading` widget 需要根据
395+
`ShimmerLoading` widget 在屏幕上的位置绘制相同的全屏渐变。
396+
308397
To be more precise, rather than assume that the shimmer
309398
should take up the entire screen,
310399
there should be some area that shares the shimmer.
@@ -317,10 +406,22 @@ Then, each `ShimmerLoading` widget gets a reference
317406
to the `Shimmer` ancestor
318407
and requests the desired size and gradient to display.
319408

409+
更准确地说,不应该假设微光效果会占据整个屏幕,
410+
而是应该有一个区域共享微光效果。
411+
这个区域可能会占据整个屏幕,也可能不会。
412+
解决这个问题的方式是在所有的 `ShimmerLoading` widget 上方
413+
定义另一个 widget,称为 `Shimmer`
414+
然后,每个 `ShimmerLoading` widget 可以引用 `Shimmer` 祖先,
415+
并请求显示所需的大小和渐变。
416+
320417
Define a new stateful widget called `Shimmer` that
321418
takes in a [`LinearGradient`][] and provides descendants
322419
with access to its `State` object.
323420

421+
定义一个新的 stateful widget,命名为 `Shimmer`
422+
它接收一个 [`LinearGradient`][]
423+
并允许后代 widget 访问其 `State` 对象。
424+
324425
<?code-excerpt "lib/main.dart (Shimmer)"?>
325426
```dart
326427
class Shimmer extends StatefulWidget {
@@ -355,6 +456,10 @@ the size of the `ShimmerState`'s `RenderBox`,
355456
and look up the position of a descendant within the
356457
`ShimmerState`'s `RenderBox`.
357458

459+
`ShimmerState` 类中添加方法,
460+
以提供对 `linearGradient``ShimmerState``RenderBox` 的大小
461+
以及查找 `ShimmerState``RenderBox` 中某个后代位置的访问权限。
462+
358463
<?code-excerpt "lib/shimmer_state.dart (ShimmerState)"?>
359464
```dart
360465
class ShimmerState extends State<Shimmer> {
@@ -387,6 +492,8 @@ class ShimmerState extends State<Shimmer> {
387492

388493
Wrap all of your screen's content with the `Shimmer` widget.
389494

495+
将屏幕上的所有内容都用 `Shimmer` widget 包裹起来。
496+
390497
<?code-excerpt "lib/main.dart (ExampleUiAnimationState)"?>
391498
```dart
392499
class _ExampleUiLoadingAnimationState extends State<ExampleUiLoadingAnimation> {
@@ -407,6 +514,8 @@ class _ExampleUiLoadingAnimationState extends State<ExampleUiLoadingAnimation> {
407514
Use the `Shimmer` widget within your
408515
`ShimmerLoading` widget to paint the shared gradient.
409516

517+
在你的 `ShimmerLoading` widget 中使用 `Shimmer` widget 来绘制共享的渐变效果。
518+
410519
<?code-excerpt "lib/shimmer_loading_state_pt2.dart (ShimmerLoadingStatePt2)"?>
411520
```dart
412521
class _ShimmerLoadingState extends State<ShimmerLoading> {
@@ -451,19 +560,33 @@ Your `ShimmerLoading` widgets now display a shared
451560
gradient that takes up all of the space within the
452561
`Shimmer` widget.
453562

563+
你的 `ShimmerLoading` widget 现在显示了一个共享的渐变效果,
564+
这个效果覆盖了 `Shimmer` widget 内部的所有空间。
565+
454566
## Animate the shimmer
455567

568+
## 给微光效果添加动画
569+
456570
The shimmer gradient needs to move in order to
457571
give the appearance of a shimmering shine.
458572

573+
微光渐变效果需要通过移动来产生光泽感。
574+
459575
The `LinearGradient` has a property called `transform`
460576
that can be used to transform the appearance of the gradient,
461577
for example, to move it horizontally.
462578
The `transform` property accepts a `GradientTransform` instance.
463579

580+
`LinearGradient` 有一个名为 `transform` 的属性,
581+
可以用来改变渐变的外观,例如,使其水平移动。
582+
`transform` 属性接受一个 `GradientTransform` 实例。
583+
464584
Define a class called `_SlidingGradientTransform` that implements
465585
`GradientTransform` to achieve the appearance of horizontal sliding.
466586

587+
定义一个名为 `_SlidingGradientTransform` 的类,
588+
来实现 `GradientTransform` 接口,以实现水平滑动的效果。
589+
467590
<?code-excerpt "lib/original_example.dart (sliding-gradient-transform)"?>
468591
```dart
469592
class _SlidingGradientTransform extends GradientTransform {
@@ -485,6 +608,9 @@ in order to create the appearance of motion.
485608
To change the percentage, configure an
486609
[`AnimationController`][] in the `ShimmerState` class.
487610

611+
渐变滑动百分比随时间变化,以创造运动的效果。
612+
要改变百分比,请在 `ShimmerState` 类中配置一个 [`AnimationController`][]
613+
488614
<?code-excerpt "lib/original_example.dart (shimmer-state-animation)" replace="/\/\/ code-excerpt-closing-bracket/}/g"?>
489615
```dart
490616
class ShimmerState extends State<Shimmer> with SingleTickerProviderStateMixin {
@@ -509,6 +635,10 @@ class ShimmerState extends State<Shimmer> with SingleTickerProviderStateMixin {
509635
Apply the `_SlidingGradientTransform` to the `gradient`
510636
by using the `_shimmerController`'s `value` as the `slidePercent`.
511637

638+
`_shimmerController``value`
639+
赋值给 `_SlidingGradientTransform``slidePercent`
640+
然后将 `_SlidingGradientTransform` 应用于 `gradient`
641+
512642
<?code-excerpt "lib/original_example.dart (linear-gradient)"?>
513643
```dart
514644
LinearGradient get gradient => LinearGradient(
@@ -526,9 +656,15 @@ The gradient now animates, but your individual
526656
as the gradient changes. Therefore, it looks like nothing
527657
is happening.
528658

659+
渐变现在已经动画化了,
660+
但你的单个 `ShimmerLoading` widget 在渐变变化时没有重新绘制自己。
661+
因此,看起来什么也没有发生。
662+
529663
Expose the `_shimmerController` from `ShimmerState`
530664
as a [`Listenable`][].
531665

666+
`ShimmerState` 中将 `_shimmerController` 暴露为一个 [`Listenable`][]
667+
532668
<?code-excerpt "lib/original_example.dart (shimmer-changes)"?>
533669
```dart
534670
Listenable get shimmerChanges => _shimmerController;
@@ -538,6 +674,10 @@ In `ShimmerLoading`, listen for changes to the ancestor
538674
`ShimmerState`'s `shimmerChanges` property,
539675
and repaint the shimmer gradient.
540676

677+
`ShimmerLoading` 中,
678+
监听祖先 `ShimmerState``shimmerChanges` 属性的变化,
679+
并重新绘制微光渐变效果。
680+
541681
<?code-excerpt "lib/original_example.dart (shimmer-loading-state)" replace="/\/\/ code-excerpt-closing-bracket/}/g"?>
542682
```dart
543683
class _ShimmerLoadingState extends State<ShimmerLoading> {
@@ -576,8 +716,14 @@ You now have a full-screen,
576716
animated shimmer effect that turns
577717
on and off as the content loads.
578718

719+
恭喜!
720+
你现在拥有了一个全屏的动画微光效果,
721+
随着内容加载,它会打开或关闭。
722+
579723
## Interactive example
580724

725+
## 交互示例
726+
581727
<?code-excerpt "lib/original_example.dart" remove="code-excerpt-closing-bracket"?>
582728
```dartpad title="Flutter shimmer loading hands-on example in DartPad" run="true"
583729
import 'package:flutter/material.dart';

0 commit comments

Comments
 (0)