【问题标题】:Flutter setState rebuilds but does not properly draw replaced widgetFlutter setState 重建但未正确绘制替换的小部件
【发布时间】:2021-08-18 13:05:16
【问题描述】:

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

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

截图:before swipeafter 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,Swipable来自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'),
        ],

【问题讨论】:

    标签: android flutter dart setstate


    【解决方案1】:

    如果您将卡片滑出屏幕,那么您只会更改其内容,而不会更改留在屏幕外的位置。

    也许在SplashCard 中添加一个key: Key(card.front) 会在每个setState() 创建一张新卡

    【讨论】:

    • 哇,谢谢,解决了!澄清一下,这是飞镖语言的优化吗?我认为调用 _createStandardSplashCard(FlashCard card) 中的构造函数 SplashCard 时会创建一个新的 SplashCard 实例?还是这个小部件中根本没有存储位置?
    • 我不确定,但是对象的位置不是它的特征,所以重建时它不会改变。
    猜你喜欢
    • 2020-11-09
    • 1970-01-01
    • 2020-08-02
    • 2017-10-02
    • 1970-01-01
    • 1970-01-01
    • 2021-09-19
    • 1970-01-01
    • 2020-09-20
    相关资源
    最近更新 更多