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

Flutter中FutureBuilder包裹AnimatedSwitcher后动画消失问题求助

问题原因

你的问题出在FutureBuilder的使用方式上:

  • 每次调用setState时,FutureBuilder会重新执行传入的_UIsetting()方法,该方法会从SharedPreferences重新读取flip值,直接覆盖当前状态,导致AnimatedSwitcher的动画还没完成就被强制切换。
  • FutureBuilder的future参数直接传入_UIsetting(),会在每次组件build时创建新的Future实例,触发不必要的异步操作,打断动画流程。
解决方案

移除FutureBuilder,改用状态变量管理加载状态,初始化操作只在initState中执行一次,后续状态更新直接操作本地变量并触发setState:

修改后的完整代码

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class myappState extends State<myapp> {
  bool flip = false;
  String id = "";
  int previous = 0; // 假设你已定义该变量

  bool isLoading = true; // 新增加载状态变量

  @override
  void initState() {
    super.initState();
    _UIsetting();
  }

  Future _UIsetting() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    flip = prefs.getBool('flip') ?? false; // 添加空值判断,避免空指针
    print("_UIsetting flip $flip");
    id = prefs.getString("ID") ?? "";
    setState(() {
      isLoading = false; // 初始化完成后关闭加载状态
    });
  }

  Future _flipCheck() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    int now = DateTime.now().millisecondsSinceEpoch;

    if ((now - previous) ~/ 3600000 >= 7) {
      flip = true;
      await prefs.setBool('flip', true);
      _upload();
    } else {
      flip = false;
      await prefs.setBool('flip', false);
    }
    setState(() {}); // 修改flip后直接触发状态更新
  }

  @override
  Widget build(BuildContext context) {
    if (isLoading) {
      return const CircularProgressIndicator();
    }

    return Container(
      child: Column(
        children: [
          // 翻转动画
          AnimatedSwitcher(
            duration: const Duration(seconds: 1),
            transitionBuilder: (Widget widget, Animation<double> animation) {
              final rotateAnim = Tween(begin: pi, end: 0.0).animate(animation);
              return AnimatedBuilder(
                animation: rotateAnim,
                child: widget,
                builder: (context, widget) {
                  // 修正判断逻辑,对比widget的key与当前flip对应的目标key
                  final targetKey = ValueKey(flip ? 0 : 1);
                  final isUnder = (widget?.key != targetKey);
                  final value = isUnder ? min(rotateAnim.value, pi / 2) : rotateAnim.value;
                  return Transform(
                    transform: Matrix4.rotationY(value),
                    alignment: Alignment.center,
                    child: widget,
                  );
                },
              );
            },
            child: flip
                ? Container(
                    key: const ValueKey(0),
                    width: MediaQuery.of(context).size.width,
                    margin: const EdgeInsets.symmetric(horizontal: 30),
                    child: Image.asset('assets/work1.png'),
                  )
                : Container(
                    key: const ValueKey(1),
                    width: MediaQuery.of(context).size.width,
                    margin: const EdgeInsets.symmetric(horizontal: 30),
                    child: Image.asset('assets/work2.png'),
                  ),
          ),
          // 根据flip状态切换按钮可点击状态
          flip
              ? Row(
                  children: [
                    ElevatedButton(
                      onPressed: _flipCheck, // 直接调用方法,无需嵌套setState
                      child: const Text("button1"),
                    ),
                    ElevatedButton(
                      onPressed: () {},
                      child: const Text("button2"),
                    ),
                  ],
                )
              : Row(
                  children: [
                    ElevatedButton(
                      onPressed: () {},
                      child: const Text("button1"),
                    ),
                    ElevatedButton(
                      onPressed: _flipCheck,
                      child: const Text("button2"),
                    ),
                  ],
                )
        ],
      ),
    );
  }

  void _upload() {
    // 你的数据上传逻辑
  }
}

// 对应的StatelessWidget(示例)
class myapp extends StatefulWidget {
  const myapp({super.key});

  @override
  myappState createState() => myappState();
}

关键修改点

  1. 移除FutureBuilder:用isLoading状态变量控制加载状态,初始化完成后再显示主内容,避免重复触发异步操作打断动画。
  2. 修正状态更新逻辑:_flipCheck中修改flip后直接调用setState,不再依赖重新读取SharedPreferences,确保动画能完整执行。
  3. 优化动画判断逻辑:调整AnimatedSwitcher中isUnder的判断条件,保证动画触发逻辑准确。
  4. 空值安全处理:读取SharedPreferences值时添加空值判断,避免空指针异常。

内容的提问来源于stack exchange,提问作者CindyLee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 08:55:32