You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter如何避免列表中CardExample对象每次被访问时重新初始化

问题原因

你的问题核心出在两处:

  1. CardExample 的 FutureBuilder 用的future直接写在了build方法里,每次组件重绘都会重新执行getRandomQuestion()拉取新的随机题,就算组件实例没有被重新初始化,只要build触发就会刷新内容
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 01:24:02