import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); static int view = 1; static PageController controllerPageView = PageController(viewportFraction: 1 / 3), controllerListView = PageController(viewportFraction: 1 / 5); static ValueNotifier theme = ValueNotifier(ThemeMode.dark); @override Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: theme, builder: (BuildContext context, ThemeMode value, Widget? child) { return MaterialApp( title: 'Flutter Demo', darkTheme: ThemeData( primarySwatch: Colors.blue, brightness: Brightness.dark, ), theme: ThemeData( primarySwatch: Colors.blue, brightness: Brightness.light, ), themeMode: value, debugShowCheckedModeBanner: false, home: const MyHomePage(), ); }); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { final List _months = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('GridView - ListView Transition'), actions: [ IconButton( onPressed: () { MyApp.theme.value = (MyApp.theme.value == ThemeMode.dark) ? ThemeMode.light : ThemeMode.dark; }, icon: ValueListenableBuilder( valueListenable: MyApp.theme, builder: (BuildContext context, ThemeMode value, Widget? child) { return Icon((value == ThemeMode.dark) ? Icons.dark_mode_rounded : Icons.light_mode_rounded); })), PopupMenuButton( initialValue: MyApp.view, onSelected: (int index) { if (MyApp.view != index) { MyApp.view = index; } if (index == 2 && MyApp.controllerPageView.hasClients && MyApp.controllerPageView.page?.round() != null) { MyApp.controllerListView = PageController(viewportFraction: 1 / 5, initialPage: (MyApp.controllerPageView.page?.round())!); } else if (index == 3 && MyApp.controllerListView.hasClients && MyApp.controllerListView.page?.round() != null) { MyApp.controllerPageView = PageController(viewportFraction: 1 / 3, initialPage: (MyApp.controllerListView.page?.round())!); } Navigator.of(context).pushReplacement(_createRoute(const MyHomePage())); }, itemBuilder: (BuildContext context) { return >[ const PopupMenuItem( value: 1, child: Text('Switch to GridView'), ), const PopupMenuDivider(), const PopupMenuItem( value: 2, child: Text('Switch to ListView'), ), const PopupMenuDivider(), const PopupMenuItem( value: 3, child: Text('Switch to PageView'), ), ]; }, ), ], elevation: 0.0, ), body: (MyApp.view == 2) ? PageView( controller: MyApp.controllerListView, scrollDirection: Axis.vertical, pageSnapping: false, padEnds: false, children: [ for (int index = 0; index < _months.length; index++) Hero( tag: index, child: Card( margin: const EdgeInsets.all(8.0), elevation: 4.0, borderOnForeground: false, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), child: AspectRatio( aspectRatio: 16 / 9, child: Center( child: Text( _months[index], style: const TextStyle( fontWeight: FontWeight.w500, fontSize: 20.0, ), ), ), ), ), ) ], ) : (MyApp.view == 1) ? GridView.count( physics: const PageScrollPhysics(), crossAxisCount: 2, padding: const EdgeInsets.all(8.0), children: [ for (int index = 0; index < _months.length; index++) Hero( tag: index, child: Card( margin: const EdgeInsets.all(8.0), elevation: 4.0, borderOnForeground: false, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), child: Center( child: Text( _months[index], style: const TextStyle( fontWeight: FontWeight.w500, fontSize: 20.0, ), ), ), ), ) ], ) : PageView( controller: MyApp.controllerPageView, children: [ for (int index = 0; index < _months.length; index++) Hero( tag: index, child: Card( margin: const EdgeInsets.all(8.0), elevation: 4.0, borderOnForeground: false, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)), child: AspectRatio( aspectRatio: 9 / 16, child: Center( child: Text( _months[index], style: const TextStyle( fontWeight: FontWeight.w500, fontSize: 20.0, ), ), ), ), ), ) ], ), ); } } Route _createRoute(Widget destination) { return PageRouteBuilder( pageBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation) => destination, transitionDuration: const Duration(milliseconds: 1200), reverseTransitionDuration: const Duration(milliseconds: 1200), transitionsBuilder: (BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { return FadeTransition( opacity: CurvedAnimation(parent: animation, curve: Curves.easeOutCirc, reverseCurve: Curves.easeOutCirc.flipped), child: child, ); }, ); }