首页 > 解决方案 > 架构/逻辑问题 - 在这种情况下,我如何只重建一个消费者小部件?- 里弗波德

问题描述

我真的把自己逼到了一个角落,不知道如何重新设计以顺利解决这个问题,同时保持我的功能。我尝试将可重复使用的小部件在树中向上移动,但这很令人困惑并且不起作用。我正在创建一个 Flutter 包,以防这可能会引起一些帮助。这是一个特定于我的错误架构/逻辑的问题,也是一个关于如何使用 Riverpod 提供程序创建可重用小部件以便仅更新必要小部件的一般问题。

我的问题是我有一个“可重用”小部件 - “NumberButtonAnimation”,在这种情况下,我的“SequentialNavigator”父级中有 5 个。它们都是按钮,它们都在监听我的逻辑服务文件 navigatorServices 中的 pageIndex 值。因此,当页面索引更改时,它们都会重建,这当然是昂贵且不必要的。

如何添加逻辑或重新设计,以便只需要重建移动按钮?

如果我认为钥匙有用,我的想法会正确吗?

/// LOGIC

final navigatorServices = ChangeNotifierProvider((ref) => NavigatorServices());

class NavigatorServices extends ChangeNotifier {
  StateCRUD stateCRUD = StateCRUD();
  int pageIndex = 1;
  int indexCount = 5;

  void nextPage() {
    if (pageIndex < indexCount) {
      pageIndex++;
      saveState();
      notifyListeners();
    }
  }

  void previousPage() {
    if (pageIndex > 1) {
      pageIndex--;
      saveState();
      notifyListeners();
    }
  }

  double buttonPosition(int buttonNumber) {
    double totalHeight = Get.height;
    double topPadding = WidgetsBinding.instance!.window.padding.top;
    double bottomPadding = WidgetsBinding.instance!.window.padding.bottom;
    double safeArea = totalHeight - (topPadding + bottomPadding);
    const double buttonWithPadding = 35.0;
    late double buttonTop;
    List<int> pageIndexes = [];
    int index = 0;
    // Current or past screen
    if (pageIndex >= buttonNumber) buttonTop = ((buttonWithPadding * buttonNumber) - buttonWithPadding);
    if (pageIndex < buttonNumber) {
      while (index < indexCount + 1) {
        pageIndexes.add(index);
        index++;
      }
      buttonTop = (buttonWithPadding * pageIndexes[buttonNumber]) + safeArea / 1.5;
    }
    return buttonTop;
  }

   ...
}


/// NUMBER BUTTON ANIMATION WIDGET

class NumberButtonAnimation extends StatelessWidget {
  const NumberButtonAnimation({Key? key, required this.buttonNumber}) : super(key: key);
  final int buttonNumber;

  @override
  Widget build(BuildContext context) {
    return Consumer(
      builder: (context, ref, child) {
        print('Number button consumer built');
        return AnimatedPositioned(
          top: ref.watch(navigatorServices).buttonPosition(buttonNumber),
          curve: Curves.bounceOut,
          duration: const Duration(milliseconds: 500),
          child: NumberButton(number: buttonNumber),
        );
      },
    );
  }
}

/// PARENT WIDGET

class SequentialNavigator extends StatelessWidget {
  const SequentialNavigator({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: 43.0,
      height: double.maxFinite,
      child: Stack(
        fit: StackFit.expand,
        alignment: Alignment.topCenter,
        children: [
          const NumberButtonAnimation(buttonNumber: 1),
          const NumberButtonAnimation(buttonNumber: 2),
          const NumberButtonAnimation(buttonNumber: 3),
          const NumberButtonAnimation(buttonNumber: 4),
          const NumberButtonAnimation(buttonNumber: 5),
        ],
      ),
    );
  }
}

当我点击下一个或上一个时的样子:

<5> flutter: Number button consumer built

这会打印 5 次,指示所有小部件正在重建,但只有一个按钮需要在任何更改时重建......

标签: flutterdartarchitectureconsumerriverpod

解决方案


您可以provider.select(...)通过仅获取您需要的内容来过滤重建

一个使用示例是:

Consumer(
  builder: (context, ref, child) {
    print('Number button consumer built');
    return AnimatedPositioned(
      top: ref.watch(navigatorServices.select((service) => service.buttonPosition(buttonNumber)),
      ...
    );
  },
);

推荐阅读