Flutter setState 重建但没有正确绘制替换的小部件

Flutter setState rebuilds but does not properly draw replaced widget

我有点困惑为什么即使调用了构建方法,也没有正确重绘小部件。

基本上画了一张卡片(SplashCard),填满了大部分屏幕。此卡可刷卡(tinder 样式)。当它向右滑动时,应该换一张新卡。因此,我只是更新了列表的索引,并且由于执行了构建方法,我希望创建并显示一张新卡片(包含来自新索引的数据)。但是,当使用 setState 并更新索引(到新卡)时,即使正确调用了所有构建方法并且新卡具有正确的数据,它也不会被绘制。屏幕保持空白。关于为什么会发生这种情况的任何想法?我哪里想错了?

截图:before swipe, after swipe

查看主要代码:

class SwipeLearning extends StatefulWidget {
  const SwipeLearning({Key? key, required this.title, required this.cardList})
      : super(key: key);

  final String title;
  final List<FlashCard> cardList;

  @override
  State<SwipeLearning> createState() => _SwipeLearningState();
}

class _SwipeLearningState extends State<SwipeLearning> {
  late double _learningProgress;
  late int _currentCardIndex;
  late Widget _currentCard;

  @override
  initState() {
    super.initState();
    _learningProgress = 0.0;
    _currentCardIndex = 0;
  }

  void _nextCard() {
    setState(() {
      _learningProgress += 1.0 / widget.cardList.length;
      _currentCardIndex++;
    });
  }

  Widget _createStandardSplashCard(FlashCard card) {
    return SplashCard(
      onSwipeRight: (details) => _nextCard(),
      front: SplashCardContent(content: Text(card.front)),
      back: SplashCardContent(content: Text(card.back)),
    );
  }

  @override
  Widget build(BuildContext context) {
    print('SwipeLearning built method invoked');

    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
        titleTextStyle: Theme.of(context).textTheme.headline6,
        backgroundColor: Colors.transparent,
        elevation: 0,
        iconTheme: IconThemeData(
          color: Colors.black,
        ),
      ),
      body: Column(
        children: [
          LinearProgressIndicator(
            backgroundColor: Colors.grey,
            value: _learningProgress,
          ),
          Expanded(
            child: _createStandardSplashCard(widget.cardList[_currentCardIndex]),
          ),
        ],
      ),
    );
  }
}

这里给出了每张卡片的定义,FlipCard来自flip_card:^0.5.0,可刷卡来自flutter_swipable: ^1.0.0.

class SplashCard extends StatelessWidget {
  const SplashCard(
      {Key? key,
      required this.front,
      required this.back,
      this.onSwipeLeft,
      this.onSwipeRight,
      this.onSwipeUp})
      : super(key: key);

  final SplashCardContent front;
  final SplashCardContent back;
  final void Function(Offset finalPosition)? onSwipeLeft;
  final void Function(Offset finalPosition)? onSwipeRight;
  final void Function(Offset finalPosition)? onSwipeUp;

  @override
  Widget build(BuildContext context) {
    print('SplashCard built method invoked');

    return Swipable(
      onSwipeLeft: onSwipeLeft,
      onSwipeRight: onSwipeRight,
      onSwipeUp: onSwipeUp,
      onPositionChanged: (details) {},
      onSwipeCancel: (position, details) {},
      onSwipeDown: (finalPosition) {},
      onSwipeEnd: (position, details) {},
      onSwipeStart: (details) {},
      child: FlipCard(
        direction: FlipDirection.HORIZONTAL,
        front: front,
        back: back,
      ),
    );
  }
}

class SplashCardContent extends StatelessWidget {
  const SplashCardContent({Key? key, required this.content}) : super(key: key);

  final Widget content;

  @override
  Widget build(BuildContext context) {
    print('SplashCardContent built method invoked');

    return Container(
      width: double.infinity,
      height: double.infinity,
      padding: const EdgeInsets.all(5.0),
      child: Card(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(5.0),
        ),
        elevation: 5.0,
        child: content,
      ),
    );
  }
}

class FlashCard {
  final String front;
  final String back;

  const FlashCard({required this.front, required this.back});
}

cardList: [
          FlashCard(front: 'hello', back: 'hallo'),
          FlashCard(front: 'I', back: 'ich'),
          FlashCard(front: 'you', back: 'du'),
          FlashCard(front: 'he', back: 'er'),
          FlashCard(front: 'she', back: 'sie'),
          FlashCard(front: 'it', back: 'es'),
          FlashCard(front: 'we', back: 'wir'),
          FlashCard(front: 'you', back: 'ihr'),
          FlashCard(front: 'they', back: 'sie'),
          FlashCard(front: 'goodbye', back: 'tschüss'),
        ],

如果你把卡片刷出屏幕,那么你只会改变它的内容,而不会改变离开屏幕的位置。

也许在 SplashCard 中添加 key: Key(card.front) 会在每个 setState()

时创建一张新卡