When push with FadeTransition and Hero animation, the icon will frozen in the screen when the page too fast to push again. Anyone has idea to solve this bug?
This is the full code example to reproduce. I am push a Hero widget to another screen, it is work to push to another screen but it is still freeze in the screen if push again before the hero widget fade out.
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:',
),
],
),
),
),
);
}
}
2
Answers
Ensure that the
Hero
widgets in both the source and destination pages have the same unique tag. This should help prevent the icon from freezing on the screen during fast navigation.Try this one,