Flutter如何避免列表中CardExample对象每次被访问时重新初始化
问题原因
你的问题核心出在两处:
CardExample的FutureBuilder用的future直接写在了build方法里,每次组件重绘都会重新执行getRandomQuestion()拉取新的随机题,就算组件实例没有被重新初始化,只要build触发就会刷新内容SwipeableWidgetController被定义在了ExampleRoute的build方法里,每次切换卡片触发setState时,controller都会被重建,连带组件状态被重置
修复方案
1. 修改CardExample.dart
把请求逻辑放到initState里仅初始化一次,同时缓存请求结果,避免重复拉取:
import 'package:flutter/material.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'dart:math'; class CardExample extends StatefulWidget { const CardExample({Key key}) : super(key: key); @override _CardExampleState createState() => _CardExampleState(); } class _CardExampleState extends State<CardExample> { Future<DocumentSnapshot> _randomQuestionFuture; DocumentSnapshot _cachedQuestion; String getRandomGeneratedId() { const int AUTO_ID_LENGTH = 20; const String AUTO_ID_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; const int maxRandom = AUTO_ID_ALPHABET.length; final Random randomGen = Random(); String id = ''; for (int i = 0; i < AUTO_ID_LENGTH; i++) { id = id + AUTO_ID_ALPHABET[randomGen.nextInt(maxRandom)]; } return id; } Future<DocumentSnapshot> getRandomQuestion() async { if (_cachedQuestion != null) return _cachedQuestion; CollectionReference myRef = FirebaseFirestore.instance.collection('questions'); while (true) { String _randomIndex = getRandomGeneratedId(); QuerySnapshot querySnapshot = await myRef.where('id', isGreaterThanOrEqualTo: _randomIndex).orderBy('id', descending: false).limit(1).get(); debugPrint(_randomIndex); if (querySnapshot.docs.isNotEmpty) { DocumentSnapshot question = querySnapshot.docs[0]; _cachedQuestion = question; debugPrint(question.data().toString()); return question; } } } @override void initState() { super.initState(); _randomQuestionFuture = getRandomQuestion(); } @override Widget build(BuildContext context) { return FutureBuilder<DocumentSnapshot>( future: _randomQuestionFuture, builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) { if (snapshot.hasError) { return Text( snapshot.error.toString(), style: TextStyle( fontSize: 24.0, color: Colors.white.withOpacity(0.8), fontWeight: FontWeight.w900, ), ); } if (snapshot.hasData && !snapshot.data.exists) { return Text("Document does not exist"); } if (snapshot.connectionState == ConnectionState.done) { Map<String, dynamic> data = snapshot.data.data() as Map<String, dynamic>; return Text( data['text'], style: TextStyle( fontSize: 24.0, color: Colors.white.withOpacity(0.8), fontWeight: FontWeight.w900, ), ); } return Text("loading"); }, ); } }
2. 修改ExampleRoute.dart
把SwipeableWidgetController移到state属性里,仅初始化一次:
import 'package:flutter/material.dart'; import 'package:swipeable_card/swipeable_card.dart'; import 'card_example.dart'; class ExampleRoute extends StatefulWidget { const ExampleRoute({Key key}) : super(key: key); @override _ExampleRouteState createState() => _ExampleRouteState(); } class _ExampleRouteState extends State<ExampleRoute> { List<CardExample> cards; int currentCardIndex; SwipeableWidgetController _cardController; @override void initState() { super.initState(); cards = [ CardExample(key: ValueKey(0)), CardExample(key: ValueKey(1)), CardExample(key: ValueKey(2)), ]; currentCardIndex = 0; _cardController = SwipeableWidgetController(); } @override Widget build(BuildContext context) { debugPrint("Card Length: ${cards.length.toString()}"); debugPrint("Current Index: $currentCardIndex"); return Scaffold( body: SafeArea( child: Column( mainAxisSize: MainAxisSize.max, children: <Widget>[ SwipeableWidget( cardController: _cardController, animationDuration: 500, horizontalThreshold: 0.85, child: cards[currentCardIndex], nextCards: <Widget>[ if (currentCardIndex + 1 < cards.length) Align( alignment: Alignment.center, ), ], onLeftSwipe: () { if (currentCardIndex + 1 == cards.length - 1) cards.add(CardExample(key: ValueKey(currentCardIndex + 2))); swipeLeft(); }, onRightSwipe: () { if (currentCardIndex != 0) swipeRight(); }, ), cardControllerRow(_cardController), ], ), ), ); } void swipeLeft() { debugPrint("New Question"); setState(() { currentCardIndex++; }); } void swipeRight() { debugPrint("Previous Question"); setState(() { currentCardIndex--; }); } Widget cardControllerRow(SwipeableWidgetController cardController) { return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[ TextButton( child: Text("Previous Question"), onPressed: () => cardController.triggerSwipeRight(), ), TextButton( child: Text("New Question"), onPressed: () => cardController.triggerSwipeLeft(), ), ], ); } }
内容的提问来源于stack exchange,提问作者futurk
相关产品推荐
相关产品推荐

