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()
时创建一张新卡
我有点困惑为什么即使调用了构建方法,也没有正确重绘小部件。
基本上画了一张卡片(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()