【问题标题】:Riverpod how to rebuild widget if provider affects UI indirectly?如果提供者间接影响 UI,Riverpod 如何重建小部件?
【发布时间】:2021-06-08 11:35:27
【问题描述】:

问题是:为什么 Riverpod 没有重建,尽管 _isHintBarStack 已更新?

这是我听hintBarStack的地方,(你可以直接跳到Widget的开头和结尾,中间部分用于设计。)

class AnswerBarBubble extends HookWidget {
  AnswerBarBubble({Key? key, required this.index}) : super(key: key);
  final int index;
  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    final _answerBar = useProvider(IndexStackProvider);
    final _randomBar = useProvider(randomBarProvider);
    final _isHintBarStack = useProvider(hintBarStack).state.contains(index);
    final _questionIndex = useProvider(questionIndexProvider).state;
    final _question = useProvider(questionsProvider);

    var _boxDecor = useState(BoxDecoration(boxShadow: [
      BoxShadow(
        offset: Offset(usableWidth * 0.005, usableWidth * 0.005),
        blurRadius: usableWidth * 0.02,
        color: Color.fromRGBO(179, 118, 84, 1),
      ),
    ], shape: BoxShape.circle, color: Color.fromRGBO(255, 237, 227, 0.85)));
    String char;
    try {
      var temp = _answerBar[index];
      char = _randomBar[temp];
      _boxDecor.value = BoxDecoration(boxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.001, usableWidth * 0.001),
          blurRadius: usableWidth * 0.005,
          color: Colors.grey.shade300,
        ),
        BoxShadow(
          offset: Offset(usableWidth * 0.0008, usableWidth * 0.0008),
          blurRadius: usableWidth * 0.004,
          color: Colors.grey.shade800,
        ),
      ], shape: BoxShape.circle, color: Color.fromRGBO(255, 237, 227, 0.6));
    } catch (e) {
      char = '';
      _boxDecor.value = BoxDecoration(boxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.005, usableWidth * 0.005),
          blurRadius: usableWidth * 0.02,
          color: Color.fromRGBO(217, 196, 184, 1),
        ),
      ], shape: BoxShape.circle, color: Color.fromRGBO(255, 237, 227, 0.85));
    }
    return Badge(
        showBadge: !_isHintBarStack,
        elevation: 10,
        badgeContent: Text('${_question[_questionIndex].answer[index]}',
            style:
                TextStyle(fontSize: usableHeight * 0.020, color: Colors.white)),
        badgeColor: Colors.blue,
        padding: EdgeInsets.all(usableWidth * 0.01),
        alignment: Alignment.center,
        position: BadgePosition.topEnd(),
        child: AnimatedContainer(
            duration: Duration(milliseconds: 200),
            child: Center(
                child: Text('$char',
                    style: TextStyle(
                        fontSize: usableHeight * 0.03, color: Colors.black))),
            height: usableWidth * 0.1,
            width: usableWidth * 0.1,
            decoration: _boxDecor.value));
  }
}



状态提供者:

final hintBarStack = StateProvider((ref) {
  final questionIndex = ref.watch(questionIndexProvider).state;
  final question = ref.read(questionsProvider);
  final length = question[questionIndex].answer.length;
  final stack = <int>[];
  for (var i = 0; i < length; i++) {
    stack.add(i);
  }
  return stack;
});

HintButton :(此按钮更新hintBarStack)(onTap 回调)




class HintButton extends HookWidget {
  const HintButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    return ElevatedButton(
        onLongPress: () {},
        onPressed: () {
          if (context.read(hintBarStack).state.length > 0) {
            final randInt =
                Random().nextInt(context.read(hintBarStack).state.length);
            context.read(hintBarStack).state.removeAt(randInt);
          }
        },
        child: Center(
          child: Icon(Icons.contact_support_sharp,
              color: Colors.black, size: usableHeight * 0.045),
        ),
        style: ElevatedButton.styleFrom(
            animationDuration: Duration(milliseconds: 300),
            shadowColor: Colors.black,
            onSurface: Colors.blueAccent,
            onPrimary: Colors.blueAccent.withOpacity(0.8),
            shape:
                StadiumBorder(side: BorderSide(width: 4, color: Colors.black)),
            primary: Colors.blueAccent.withOpacity(0.8),
            fixedSize: Size(usableWidth * 0.6, usableHeight * 0.06)));
  }
}

让我对riverpod感到困惑的主要事情是,我一直观察到riverpod只能成功重建小部件,当我在文本小部件中使用侦听器时,我的意思是它们可以直接在屏幕上看到,在这些直接的UI使用场景中没有问题。例如在 AnswerBarBubble(第一段代码)中:

Text('$char) -> Riverpod 在字符更新时重建小部件。(直接使用 UI)

Badge(showBadge : _isHintBarStack, -> Riverpod 在 _isHintBarStack 更新时不会重建小部件。 (小部件参数)

【问题讨论】:

  • 这应该可以。你能分享你的代码吗?
  • @AlexHartford 你能看看吗?我更新了。
  • 您的 StateProvider 做得太多了。 StateProvider 用于从外部修改简单状态。尝试将其转换为 StateNotifierProvider,应该可以解决您的问题。
  • 耶!!它有效,非常感谢您的解决方案。请继续帮助riverpod社区,我阅读了你所有的stackoverflowriverpod答案并从他们身上学到了很多。
  • 我很感激,不客气。您应该发布这个问题的答案,包括解决您的问题的代码,我认为它也可以帮助其他人!

标签: flutter riverpod


【解决方案1】:

感谢 Alex Hartford,问题是 StateProvider 的任务过多,我将 StateProvider 转换为 StateNotifierProvider 并解决了我的问题。

这是 AnswerBubble 小部件:


class AnswerBarBubble extends HookWidget {
  AnswerBarBubble({Key? key, required this.index}) : super(key: key);
  final int index;
  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    final _answerBar = useProvider(IndexStackProvider);
    final _randomBar = useProvider(randomBarProvider);
    final _isHintBarStack = useProvider(hintBarStack).contains(index);
    final _questionIndex = useProvider(questionIndexProvider).state;
    final _question = useProvider(questionsProvider);

    var _boxDecor = useState(BoxDecoration(boxShadow: [
      BoxShadow(
        offset: Offset(usableWidth * 0.005, usableWidth * 0.005),
        blurRadius: usableWidth * 0.02,
        color: Color.fromRGBO(179, 118, 84, 1),
      ),
    ], shape: BoxShape.circle, color: Color.fromRGBO(255, 237, 227, 0.85)));
    String char;
    try {
      var temp = _answerBar[index];
      char = _randomBar[temp];
      _boxDecor.value = BoxDecoration(boxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.001, usableWidth * 0.001),
          blurRadius: usableWidth * 0.005,
          color: Colors.grey.shade300,
        ),
        BoxShadow(
          offset: Offset(usableWidth * 0.0008, usableWidth * 0.0008),
          blurRadius: usableWidth * 0.004,
          color: Colors.grey.shade800,
        ),
      ], shape: BoxShape.circle, color: Color.fromRGBO(255, 237, 227, 0.6));
    } catch (e) {
      char = '';
      _boxDecor.value = BoxDecoration(boxShadow: [
        BoxShadow(
          offset: Offset(usableWidth * 0.005, usableWidth * 0.005),
          blurRadius: usableWidth * 0.02,
          color: Color.fromRGBO(217, 196, 184, 1),
        ),
      ], shape: BoxShape.circle, color: Color.fromRGBO(255, 237, 227, 0.85));
    }
    return Stack(
      alignment: Alignment.center,
      clipBehavior: Clip.hardEdge,
      children: [
        Badge(
            showBadge: !_isHintBarStack,
            elevation: 10,
            badgeContent: Text('${_question[_questionIndex].answer[index]}',
                style: TextStyle(
                    fontSize: usableHeight * 0.020, color: Colors.white)),
            badgeColor: Colors.blue,
            padding: EdgeInsets.all(usableWidth * 0.01),
            alignment: Alignment.center,
            position: BadgePosition.topEnd(),
            child: AnimatedContainer(
                duration: Duration(milliseconds: 200),
                child: Center(
                    child: Text('$char',
                        style: TextStyle(
                            fontSize: usableHeight * 0.03,
                            color: Colors.black))),
                height: usableWidth * 0.1,
                width: usableWidth * 0.1,
                decoration: _boxDecor.value))
      ],
    );
  }
}


StateNotifierProvider:

final hintBarStack = StateNotifierProvider<HintBarStack, List<int>>((ref) {
  final _question = ref.read(questionsProvider);
  final _index = ref.watch(questionIndexProvider).state;
  final _length = _question[_index].answer.length;
  final _state = <int>[];
  for (var i = 0; i < _length; i++) {
    _state.add(i);
  }
  return HintBarStack(_state);
});

提示按钮:

class HintButton extends HookWidget {
  const HintButton({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final usableWidth = MediaQuery.of(context).size.width -
        (MediaQuery.of(context).padding.left +
            MediaQuery.of(context).padding.right);
    final usableHeight = MediaQuery.of(context).size.height -
        (MediaQuery.of(context).padding.bottom +
            MediaQuery.of(context).padding.top);
    return ElevatedButton(
        onLongPress: () {},
        onPressed: () {
          if (context.read(hintBarStack).length > 0) {
            final randInt = Random().nextInt(context.read(hintBarStack).length);
            context.read(hintBarStack.notifier).pop(randInt);
          }
        },
        child: Center(
          child: Icon(Icons.contact_support_sharp,
              color: Colors.black, size: usableHeight * 0.045),
        ),
        style: ElevatedButton.styleFrom(
            animationDuration: Duration(milliseconds: 300),
            shadowColor: Colors.black,
            onSurface: Colors.blueAccent,
            onPrimary: Colors.blueAccent.withOpacity(0.8),
            shape:
                StadiumBorder(side: BorderSide(width: 4, color: Colors.black)),
            primary: Colors.blueAccent.withOpacity(0.8),
            fixedSize: Size(usableWidth * 0.6, usableHeight * 0.06)));
  }
}

状态通知器:

class HintBarStack extends StateNotifier<List<int>> {
  HintBarStack(List<int> state) : super(state);
  void pop(int index) {
    var temp = state;
    temp.removeAt(index);
    state = [...temp];
  }
}

【讨论】:

    猜你喜欢
    • 2022-11-11
    • 2023-02-14
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    • 1970-01-01
    • 2021-08-28
    相关资源
    最近更新 更多