如果提供者间接影响 UI,Riverpod 如何重建小部件?

时间:2021-06-08 11:35:27

标签: flutter riverpod

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

这是我听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, -> 当 _isHintBarStack 更新时,Riverpod 不会重建小部件。 (小部件参数)

1 个答案:

答案 0 :(得分: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];
  }
}