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

Flutter中FadeTransition+Hero动画快速跳转图标冻结问题求助

Flutter Hero组件结合FadeTransition快速跳转时图标冻结异常问题

在Flutter开发场景下,当结合FadeTransition转场动画与Hero组件进行页面跳转时,若在Hero组件完成淡出前快速触发再次跳转,会出现图标冻结在屏幕上的异常。以下是可复现该Bug的完整代码示例,恳请各位开发者提供解决方案。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class AppRoutes {
  static MaterialPageRoute? getRoute(RouteSettings settings) {
    switch (settings.name) {
      case "/":
        return MainRoute(
          MyHomePage(),
          settings: settings,
        );
    }
  }
}

class MainRoute<T> extends MaterialPageRoute<T> {
  MainRoute(
    Widget widget, {
    RouteSettings? settings,
  }) : super(builder: (_) => widget, settings: settings);
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      onGenerateRoute: (RouteSettings settings) => AppRoutes.getRoute(
        settings,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.of(context).push(
            MaterialPageRoute(
              builder: (context) => TestScreen(),
            ),
          );
        },
        child: const Icon(Icons.route),
      ),
    );
  }
}

class TestScreen extends StatefulWidget {
  const TestScreen({
    super.key,
    this.isSuccess = false,
  });

  final bool isSuccess;

  @override
  State<TestScreen> createState() => _TestScreenState();
}

class _TestScreenState extends State<TestScreen> {
  @override
  void initState() {
    super.initState();
    _redirectToDetailPage();
  }

  void _redirectToDetailPage() async {
    Future.delayed(const Duration(seconds: 2), () {
      Navigator.push(
        context,
        PageRouteBuilder(
          maintainState: false,
          opaque: true,
          pageBuilder: (_, Animation<double> start, Animation<double> end) {
            return TestUnsuccess(
              test: end,
            );
          },
          transitionsBuilder: (context, animation, secondaryAnimation, child) {
            return FadeTransition(
              opacity: animation,
              child: child,
            );
          },
          transitionDuration: Duration(milliseconds: 2000),
        ),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PopScope(
        canPop: false,
        child: SafeArea(
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Hero(
                  tag: 'payment_icon',
                  child: Icon(
                    Icons.abc,
                    size: 40,
                  ),
                ),
                SizedBox(
                  height: 32.0,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class TestUnsuccess extends StatefulWidget {
  final Animation<double> test;

  TestUnsuccess({
    required this.test,
  });

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

class TestUnsuccessState extends State<TestUnsuccess> {
  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: PopScope(
        canPop: false,
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Hero(
                tag: 'payment_icon',
                child: Icon(
                  Icons.abc,
                  size: 40,
                ),
              ),
              SizedBox(
                height: 16.0,
              ),
              ElevatedButton(
                child: Icon(
                  Icons.home_filled,
                ),
                onPressed: () {
                  Navigator.of(context).pushNamedAndRemoveUntil(
                    "/",
                    ModalRoute.withName('/'),
                  );

                  Navigator.of(context).push(
                    MaterialPageRoute(
                      builder: (context) => TestAnother(),
                    ),
                  );
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class TestAnother extends StatefulWidget {
  @override
  State<TestAnother> createState() => _TestAnotherState();
}

class _TestAnotherState extends State<TestAnother> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'You have pushed the button this many times:',
              ),
            ],
          ),
        ),
      ),
    );
  }
}

图标冻结效果截图


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 23:20:21