如何防止带有回调的子树在 Flutter 中重新渲染?

如何解决如何防止带有回调的子树在 Flutter 中重新渲染?

我是 Flutter 的新手,有一些性能问题。对于我的应用程序,我创建了一个自定义侧边栏菜单,灵感来自

custom sidebar menu

为此,我创建了一个作为父屏幕的有状态顶级小部件。它包含一个 Stack 小部件,按钮上有导航屏幕,顶部有一个内容屏幕。用户应该能够通过两种方式打开/关闭菜单

  1. 按下内容屏幕左上角的汉堡菜单图标(当它完全打开时,或者像第一张图片那样移到一边)
  2. 菜单打开时向右滑动,在菜单关闭时向左滑动。

为了满足第 2 点,我在父屏幕上添加一个 GestureDetector,以便在整个屏幕中检测到滑动,从而在全视图中将内容屏幕动画化到侧面/背面。为了满足第 1 点,我将 onPress 回调传递给内容屏幕(将其传递给汉堡 iconButton),它也执行顶级动画。但是,阅读文档 (stateful performance considerations) 时,随着重建的进行,这种顶级有状态小部件似乎对性能有害。由于回调,我无法使我的内容屏幕成为 const 小部件(这是建议的解决方案)。这显然是次优的,因为在内容屏幕中,只有图标在菜单打开时有动画变化(图标从汉堡变成箭头)。

如何最小化子树中的重新渲染次数?有没有办法将屏幕作为 const 小部件传递,即使它有回调?或者目前的方法是否令人满意?

我目前拥有的代码如下:

class ParentScreen extends StatefulWidget {
  const ParentScreen({Key? key}) : super(key: key);

  @override
  _ParentScreenState createState() => _ParentScreenState();
}

class _ParentScreenState extends State<ParentScreen> {
  bool isMenuOpen = false;
  double xOffset = 0;
  double yOffset = 0;
  double rotationAngle = 0;
  double scaleFactor = 1;

  double toradians(double degrees) => degrees * math.pi / 180.0;

  void animateMenu() {
    setState(() {
      ...
      isMenuOpen = !isMenuOpen;
    });
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      // Detect user swipe to navigate between the screens
      child: GestureDetector(
        onHorizontalDragEnd: (DragEndDetails details) {
          if (details.primaryVeLocity != null) {
            if (details.primaryVeLocity! > 0) {
              // Right swipe,close menu if open
              if (isMenuOpen) animateMenu();
            } else if (details.primaryVeLocity! < 0) {
              // Left swipe,open menu if closed
              if (!isMenuOpen) animateMenu();
            }
          }
        },child: Scaffold(
          body: Stack(
            children: <Widget>[
              const DrawerScreen(),// Screen with navigation information
              AnimatedContainer(
                transform: Matrix4.translationValues(xOffset,yOffset,0)
                  ..scale(scaleFactor)
                  ..rotateZ(toradians(rotationAngle)),duration: const Duration(milliseconds: 300),child: HomeScreen( // Screen with custom content 
                  onMenuPress: animateMenu,),],);
  }
}

解决方法

好吧,您不需要使父小部件成为有状态的小部件。

首先制作实际菜单,包括它的动画,它位于小部件上,该小部件会覆盖其他所有内容..(类似于您在 Stack 小部件中所说的内容)。

然后创建一个位于小部件树之外的对象(通常在 flutter-world 中称为 BLoC) - ChangeNotifierStream 并将其注入无状态小部件(最简单的方法是使用provider 包,但您也可以使用 InheritedWidget

当你想显示菜单时,你只需改变这个外部对象的状态,它会通知菜单小部件展开。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?