在 Flutter 中,如何解决 `AnimatedCrossFade` 低效设计?
In Flutter, how to solve `AnimatedCrossFade` inefficient design?
AnimatedCrossFade
的一个问题是您必须提供两个 children,即使只显示其中一个。
如果 children 中的一个(或两个)复杂而沉重,则效率不高。
我尝试提供 Builder
作为 child,像这样:
AnimatedCrossFade(
firstChild: widget1,
secondChild: Builder(builder: widget2builder),
duration: const Duration(milliseconds: 500),
crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),
var widget2builder = (context) {
print("Building widget 2");
return Container(),
);
};
但是,这会立即打印 Building widget 2
,即使显示的是第一个小部件,因此根本不需要小部件 2。
这是一个完整的、运行可行的例子:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
bool toggle;
@override
void initState() {
super.initState();
toggle = true;
}
@override
Widget build(BuildContext context) {
var toggleButton = Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
child: const Text("Toggle"),
color: Colors.grey,
onPressed: () {
setState(() {
toggle = !toggle;
});
},
),
);
var widget1 = Container(
key: UniqueKey(),
color: Colors.blue,
width: 200.0,
child: const Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt "
"ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat.",
),
);
var widget2builder = (context) {
print("Building widget 2.");
return Container(
key: UniqueKey(),
color: Colors.red,
width: 200.0,
child: const Text(
"I am ready for my closeup.",
),
);
};
return MaterialApp(
home: Material(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
toggleButton,
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text("Some text above."),
AnimatedCrossFade(
firstChild: widget1,
secondChild: Builder(builder: widget2builder),
duration: const Duration(milliseconds: 500),
crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),
const Text("Some text below."),
],
),
],
),
),
);
}
}
如果你 运行 这个,你会看到 Building widget 2
被打印到控制台,但显示的是小部件 1。
我的问题:
AnimatedCrossFade
构建它不使用的小部件有什么原因吗?
我怎样才能避免这个问题并有效地使用 AnimatedCrossFade
?
这是预期的行为。
正如 dart 团队所说,您应该期望随时调用 build
方法。
build
被设计为便宜且无副作用。
构建小部件的事实并不意味着它会在屏幕上呈现。 Opacity
不透明度为 0 实际上缩短了绘画过程(并且在完全不透明时有其他优化)。
如果这会导致问题,那么您应该改用 AnimatedSwitcher
,它会在其子项被替换时播放动画。
我想补充一下 Rémi 的回答,在问了这个问题之后我发布了一个包来解决它,叫做 AnimatedSizeAndFade
:
https://pub.dev/packages/animated_size_and_fade
它与其他类似小部件相比如何:
使用 AnimatedCrossFade 时,您必须同时保留 firstChild 和 secondChild,而使用 AnimatedSizeAndFade 则不需要。
使用 AnimatedSwitcher,您可以简单地更改其 child,但随后它只会对淡入淡出进行动画处理,而不会对大小进行动画处理。
AnimatedContainer 也不起作用,除非您事先知道 children 的大小。
AnimatedCrossFade
的一个问题是您必须提供两个 children,即使只显示其中一个。
如果 children 中的一个(或两个)复杂而沉重,则效率不高。
我尝试提供 Builder
作为 child,像这样:
AnimatedCrossFade(
firstChild: widget1,
secondChild: Builder(builder: widget2builder),
duration: const Duration(milliseconds: 500),
crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),
var widget2builder = (context) {
print("Building widget 2");
return Container(),
);
};
但是,这会立即打印 Building widget 2
,即使显示的是第一个小部件,因此根本不需要小部件 2。
这是一个完整的、运行可行的例子:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
bool toggle;
@override
void initState() {
super.initState();
toggle = true;
}
@override
Widget build(BuildContext context) {
var toggleButton = Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
child: const Text("Toggle"),
color: Colors.grey,
onPressed: () {
setState(() {
toggle = !toggle;
});
},
),
);
var widget1 = Container(
key: UniqueKey(),
color: Colors.blue,
width: 200.0,
child: const Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt "
"ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat.",
),
);
var widget2builder = (context) {
print("Building widget 2.");
return Container(
key: UniqueKey(),
color: Colors.red,
width: 200.0,
child: const Text(
"I am ready for my closeup.",
),
);
};
return MaterialApp(
home: Material(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
toggleButton,
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text("Some text above."),
AnimatedCrossFade(
firstChild: widget1,
secondChild: Builder(builder: widget2builder),
duration: const Duration(milliseconds: 500),
crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),
const Text("Some text below."),
],
),
],
),
),
);
}
}
如果你 运行 这个,你会看到 Building widget 2
被打印到控制台,但显示的是小部件 1。
我的问题:
AnimatedCrossFade
构建它不使用的小部件有什么原因吗?我怎样才能避免这个问题并有效地使用
AnimatedCrossFade
?
这是预期的行为。
正如 dart 团队所说,您应该期望随时调用 build
方法。
build
被设计为便宜且无副作用。
构建小部件的事实并不意味着它会在屏幕上呈现。 Opacity
不透明度为 0 实际上缩短了绘画过程(并且在完全不透明时有其他优化)。
如果这会导致问题,那么您应该改用 AnimatedSwitcher
,它会在其子项被替换时播放动画。
我想补充一下 Rémi 的回答,在问了这个问题之后我发布了一个包来解决它,叫做 AnimatedSizeAndFade
:
https://pub.dev/packages/animated_size_and_fade
它与其他类似小部件相比如何:
使用 AnimatedCrossFade 时,您必须同时保留 firstChild 和 secondChild,而使用 AnimatedSizeAndFade 则不需要。
使用 AnimatedSwitcher,您可以简单地更改其 child,但随后它只会对淡入淡出进行动画处理,而不会对大小进行动画处理。
AnimatedContainer 也不起作用,除非您事先知道 children 的大小。