- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
下面是一个最小的应用程序,表明了我的担忧。如果您运行它,您会看到即使只有一个项目的数据发生了变化,每个可见项目的构建方法也会运行。
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyList extends StatelessWidget {
final List<int> items;
MyList(this.items);
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
print("item $index built");
return ListTile(
title: Text('${items[index]}'),
);
});
}
}
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<int> items = List<int>.generate(10000, (i) => i);
void _incrementItem2() {
setState(() {
this.items[1]++;
});
}
@override
Widget build(BuildContext context) {
final title = 'Long List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Column(
children: <Widget>[
MyButton(_incrementItem2),
Expanded(child: MyList(this.items))
],
),
),
);
}
}
class MyButton extends StatelessWidget {
final Function incrementItem2;
void handlePress() {
incrementItem2();
}
MyButton(this.incrementItem2);
@override
Widget build(BuildContext context) {
return TextButton(
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(Colors.blue),
),
onPressed: handlePress,
child: Text('increment item 2'),
);
}
}
在 React/React Native 中,我会使用 shouldComponentUpdate 或 UseMemo 来防止不必要的渲染。我想在 Flutter 中做同样的事情。
最佳答案
我会争辩说,当您看到性能问题/jankiness 时进行优化,但这是概率问题。在这样做之前不值得这样做。 Flutter 团队做了一个 short video about this .
请记住,虽然您可能会看到小部件上发生重建,但您可以使用 print
检测到这些重建。语句,您没有看到单独发生的 Flutter 优化渲染。
Flutter 有一个小部件树、一个元素树和一个渲染对象树。
Image taken from Architectural Overview .
小部件树是我们手工编码的 Dart 蓝图,用于我们想要构建的内容。 (只有左树上的蓝色项目。白色项目是底层的:我们不直接写。)
元素树是 Flutter 对我们蓝图的解释,更详细地说明了使用哪些实际组件以及布局和渲染所需的内容。
renderObject 树将生成一个项目列表,其中包含需要在屏幕上光栅化的尺寸、层深度等详细信息。
蓝图可能会被多次删除和重写,但这并不意味着所有(甚至许多)底层组件都被销毁/重新创建/重新渲染/重新定位。未更改的组件将被重新使用。
假设我们正在 build 一个包含水槽和浴缸的浴室。业主决定交换水槽和浴缸的位置。承包商不使用大锤粉碎陶瓷,购买/运输并安装全新的水槽和浴缸。他只是将每个人分开并交换他们的位置。
这是一个使用 AnimatedSwitcher
的人为例子:
child: AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: Container(
key: key,
color: color,
padding: EdgeInsets.all(30),
child: Text('Billy'))),
AnimatedSwitcher
应该在他们改变时交叉淡入淡出它的 child 。 (在这种情况下说从蓝色到绿色。)但是如果
key
未提供,
AnimatedSwitcher
不会被重建,也不会做交叉淡入淡出动画。
AnimatedSwitcher
,它会检查它的 child 是否有明显的变化,即不同的树结构、不同的元素类型等,但它不会进行深入检查(我认为成本太高了)。它在相同的树位置(直接子节点)看到相同的对象类型(
Container
)并保留
AnimatedSwitcher
无需重建它。结果是
Container
(当它因为颜色改变而重建时)从绿色变为蓝色,没有动画。
key
至
Container
帮助 Flutter 在分析
AnimatedSwitcher
时将它们识别为不同的用于优化的子树。现在 Flutter 将重建
AnimatedSwitcher
在 500 毫秒的持续时间内大约 30 次以直观地显示动画。 (Flutter 的目标是在大多数设备上达到 60fps。)
AnimatedSwitcher
在复制/粘贴示例中使用:
Container
,允许 Flutter 发现差异并为 AnimatedSwitcher
进行重建import 'package:flutter/material.dart';
class AnimatedSwitcherPage extends StatefulWidget {
@override
_AnimatedSwitcherPageState createState() => _AnimatedSwitcherPageState();
}
class _AnimatedSwitcherPageState extends State<AnimatedSwitcherPage> {
Color color = Colors.lightGreenAccent;
ValueKey key;
@override
void initState() {
super.initState();
key = ValueKey(color.value);
Future.delayed(Duration(milliseconds: 1500), () => _update(useKey: false));
// this initial color change happens WITHOUT key changing
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animation Switcher'),
actions: [
IconButton(icon: Icon(Icons.refresh), onPressed: _restartWithKey)
],
),
body: Center(
child: AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: Container(
key: key,
color: color,
padding: EdgeInsets.all(30),
child: Text('Billy'))),
),
);
}
void _update({bool useKey}) {
setState(() {
color = Colors.lightBlueAccent;
if (useKey) key = ValueKey(color.value);
});
}
void _restartWithKey() {
setState(() {
color = Colors.lightGreenAccent; // reset color to green
});
Future.delayed(Duration(milliseconds: 1500), () => _update(useKey: true));
// this refresh button color change happens WITH a key change
}
}
评论附录
AnimatedSwitcher
是
StatefulWidget
.它在构建之间保存前一个子小部件。当一个新的构建发生时,它会比较旧的 child 和新的 child 。 (参见
Widget.canUpdate()
方法进行比较。)
.canUpdate()
),
AnimatedSwitcher
基本上是一个不需要的包装器:它不会做任何特别的事情,但会进行重建以维护其最新的 child (?)。我不得不承认这是一个糟糕的例子选择。
关于flutter - 如何防止 Flutter 中不必要的渲染?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67358514/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!