文章
问答
冒泡
flutter使用ValueNotifier实现局部重新渲染
在flutter项目中,我们通常会需要根据值的变化来让界面重新渲染,从而展示新的效果。一般情况下,我们会直接使用 setState((){}) 让整个组件进行重新渲染。但是在有些情况下,例如我们在快速的进行重新赋值,如果这个时候,我们依旧使用 setState 触发整个组件的重新渲染,就很有可能导致操作卡顿甚至渲染抖动,这是由于,值的快速变化,而引起组件的快速重复渲染。例如,我们在做滚动选择器的时候,需要实时展示选择的值。
 
界面效果如下:
由界面可以看出,我们在滚动选择时间的时候,需要在顶部,实时展示出选择的结果。这个时候,如果我们让组件整体重新渲染的话,就会引起选择器的抖动,因为页面重新渲染的时候,会根据值来进行行数定位,而滚动的每一次操作距离是小于每一项的行高的。这样一来就会出现抖动效果。
解决思路
为了避免类似的情况,我们期望的效果是,每次值更新的时候,只重新渲染顶部时间,而不去做整体重新渲染,也就是局部渲染。在flutter 中,我们可以通过 ValueNotifier 来实现这个效果。一般来说,这是一个类似监听值变化的组件,当值监听的值发生了变化,那么就会触发内部的重新渲染,而其他部分则不会。
关键代码
ValueNotifier<DateTime?> _selectedDateTime = ValueNotifier(null);

Widget build(BuildContext context) {
  AntThemeData themeData = AntTheme.of(context);
  return Column(
    mainAxisSize: MainAxisSize.min,
    children: [
      Container(
        height: 40,
        decoration: BoxDecoration(
            border:
                Border(bottom: BorderSide(color: themeData.colorBorder, width: 0.5))),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Expanded(
                child: ValueListenableBuilder(
                    valueListenable: _selectedDateTime,
                    builder: (context, value, child) {
                      return Container(
                          padding: EdgeInsets.symmetric(horizontal: 16),
                          child: _Label(
                            index: _showIndex,
                            selectedDateTime: value,
                            onIndexChange: (index) {
                              setState(() {
                                _showIndex = index;
                              });
                            },
                          ));
                    })),
            GestureDetector(
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 16),
                child: Text("确定",
                    style: TextStyle(color: themeData.colorPrimary)),
              ),
              onTap: () {
                widget.onOk?.call(_selectedDateTime.value);
              },
            )
          ],
        ),
      ),
      ......
    ],
  );
}
当 _selectedDateTime 值发生变化的时候,就只会触发 ValueListenableBuilder 内部的重新渲染。
根据以上的结论,在复杂界面中可以通过局部渲染的方案优化界面的渲染效果。
 
 
flutter

关于作者

落雁沙
非典型码农
获得点赞
文章被阅读