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

Flutter中如何在AnimatedSwitcher动画后延迟显示容器文本?

解决Flutter闪卡翻转时提前显示反面文本的问题

问题根源

  1. 文本与状态同步过早:当前代码中卡片文本直接绑定isFront状态,isFront切换时文本立刻更新,而AnimatedSwitcher的动画尚未完成,导致反面文本提前暴露。
  2. 自动切换索引逻辑干扰:_toggleCardSide里的延迟切换卡片索引逻辑,会在翻转动画过程中就更新卡片内容,进一步加剧了提前显示的问题。

修复步骤

1. 拆分正反卡片为独立Widget

把正面和反面卡片做成两个独立的Widget,让AnimatedSwitcher负责切换这两个Widget,而非在同一个Widget里动态修改文本。这样动画过程中,新旧Widget会各自保持自身内容,不会提前替换文本。

修改_buildFlashcard方法:

Widget _buildFlashcard(BuildContext context) {
  if (_viewModel.flashcards.isEmpty) {
    return const Expanded(
      child: Center(
        child: Text(
          'No flashcard available',
          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
        ),
      ),
    );
  }

  final currentCard = _viewModel.flashcards[_viewModel.currentIndex];

  return Expanded(
    child: GestureDetector(
      onTap: _toggleCardSide,
      child: AnimatedSwitcher(
        duration: const Duration(milliseconds: 500),
        transitionBuilder: (child, animation) {
          final rotate = Tween(begin: pi, end: 0.0).animate(animation);
          return AnimatedBuilder(
            animation: rotate,
            child: child,
            builder: (context, child) {
              final isUnder = (child?.key == const ValueKey(false));
              final value = isUnder ? min(rotate.value, pi / 2) : rotate.value;
              return Transform(
                transform: Matrix4.rotationY(value),
                alignment: Alignment.center,
                child: child,
              );
            },
          );
        },
        child: isFront
            ? _buildCardFace(
                key: const ValueKey(true),
                text: currentCard.frontText,
              )
            : _buildCardFace(
                key: const ValueKey(false),
                text: currentCard.backText,
              ),
      ),
    ),
  );
}

// 提取通用卡片模板Widget
Widget _buildCardFace({required Key key, required String text}) {
  return Container(
    key: key,
    width: MediaQuery.of(context).size.width * 0.9,
    height: MediaQuery.of(context).size.height * 0.6,
    padding: const EdgeInsets.all(20),
    decoration: BoxDecoration(
      color: Colors.grey[300],
      borderRadius: BorderRadius.circular(16),
      border: Border.all(
        color: const Color(0xFF4B39EF)
      ),
      boxShadow: const [
        BoxShadow(
          color: Colors.black26,
          blurRadius: 4,
          offset: Offset(0, 2),
        ),
      ],
    ),
    child: Center(
      child: Text(
        text,
        textAlign: TextAlign.center,
        style: Theme.of(context).textTheme.bodyLarge,
      ),
    ),
  );
}

2. 修正卡片切换逻辑

移除_toggleCardSide中的延迟和自动切换索引逻辑,让点击卡片仅负责翻转正反面,卡片切换由底部的Success/Failure按钮处理:

Future<void> _toggleCardSide() async {
  if (_viewModel.flashcards.isNotEmpty && 
      _viewModel.flashcards[_viewModel.currentIndex].frontText.isNotEmpty) {
    setState(() {
      isFront = !isFront; // 仅切换正反面,不自动切换卡片
    });
  }
}

3. 保留按钮切换时的重置逻辑

底部按钮的代码已经正确设置isFront = true,保持现有逻辑即可,确保切换到新卡片时默认显示正面。

为什么之前的延迟没用?

setState会立即触发UI重建,第一次setState切换isFront时文本已经同步更新,延迟后的setState又会切换卡片索引,导致动画过程中内容多次变化,无法达到预期效果。拆分独立Widget后,AnimatedSwitcher会管理新旧Widget的过渡,确保动画过程中各自内容稳定,直到动画完成才完全替换。

内容的提问来源于stack exchange,提问作者Fabian Lüdicke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:57:04