splash animation added.
							parent
							
								
									2584e6cc6e
								
							
						
					
					
						commit
						12cef74f16
					
				
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								| @ -0,0 +1 @@ | |||||||
|  | {"nm":"Splash Launch 1","ddd":0,"h":927,"w":430,"meta":{"g":"LottieFiles Figma v92"},"layers":[{"ty":4,"nm":"Ellipse 54","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[19.5,19.5],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[19.5,19.5],"t":60},{"s":[628.5,628.5],"t":120}]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[216,464],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[216.5,464.5],"t":60},{"s":[225.5,473.5],"t":120}]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[0],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[0],"t":60},{"s":[100],"t":120}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[{"c":true,"i":[[0,0],[10.493846153846153,0],[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153]],"o":[[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153],[10.493846153846153,0],[0,0]],"v":[[38,19],[19,38],[0,19],[19,0],[38,19]]}],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[{"c":true,"i":[[0,0],[10.493846153846153,0],[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153]],"o":[[0,10.493846153846153],[-10.493846153846153,0],[0,-10.493846153846153],[10.493846153846153,0],[0,0]],"v":[[38,19],[19,38],[0,19],[19,0],[38,19]]}],"t":60},{"s":[{"c":true,"i":[[0,0],[341.5871678599841,0],[0,341.5871678599841],[-341.5871678599841,0],[0,-341.5871678599841]],"o":[[0,341.5871678599841],[-341.5871678599841,0],[0,-341.5871678599841],[341.5871678599841,0],[0,0]],"v":[[1237,618.5],[618.5,1237],[0,618.5],[618.5,0],[1237,618.5]]}],"t":120}]}},{"ty":"st","bm":0,"hd":false,"nm":"","lc":1,"lj":1,"ml":4,"o":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[20],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[20],"t":60},{"s":[100],"t":120}]},"w":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1],"t":60},{"s":[20],"t":120}]},"c":{"a":0,"k":[0.9295,0.1098,0.1687]}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[1,1,1]},"r":1,"o":{"a":0,"k":100}}],"ind":1},{"ty":4,"nm":"Group 8232","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[155,404]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":0},{"o":{"x":0,"y":0},"i":{"x":1,"y":1},"s":[0],"t":60.06},{"s":[100],"t":120}]}},"shapes":[],"ind":2},{"ty":4,"nm":"Rectangle 17364","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[200,326.5]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[-207.54,1178.76],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[565.46,-310.24],"t":60},{"s":[565.46,-310.24],"t":120.12}]},"r":{"a":0,"k":30},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[100],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[100],"t":60},{"s":[0],"t":120.12}]}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,-110.38],[0,0],[110.38,0],[0,0],[0,110.38],[0,0],[-110.38,0],[0,0]],"o":[[0,0],[0,110.38],[0,0],[-110.38,0],[0,0],[0,-110.38],[0,0],[110.38,0]],"v":[[400,200],[400,453],[200,653],[200,653],[0,453],[0,200],[200,0],[200,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":0,"k":[0.9295,0.1098,0.1687]},"r":1,"o":{"a":0,"k":100}}],"ind":3},{"ty":4,"nm":"Symptoms Checker Bg","sr":1,"st":0,"op":121.06,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[215,463.5]},"s":{"a":0,"k":[100,100]},"sk":{"a":0,"k":0},"p":{"a":0,"k":[215,463.5]},"r":{"a":0,"k":0},"sa":{"a":0,"k":0},"o":{"a":0,"k":100}},"shapes":[{"ty":"sh","bm":0,"hd":false,"nm":"","d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[430,0],[430,927],[0,927],[0,0]]}}},{"ty":"fl","bm":0,"hd":false,"nm":"","c":{"a":1,"k":[{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1,1,1],"t":0},{"o":{"x":0.82,"y":-0.01},"i":{"x":0.58,"y":1},"s":[1,1,1],"t":60},{"s":[0.9295,0.1098,0.1687],"t":120}]},"r":1,"o":{"a":0,"k":100}}],"ind":4}],"v":"5.7.0","fr":60,"op":120.06,"ip":0,"assets":[]} | ||||||
| @ -0,0 +1,382 @@ | |||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/app_assets.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/core/app_export.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/presentation/authentication/login.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/theme/colors.dart'; | ||||||
|  | import 'package:hmg_patient_app_new/widgets/transitions/fade_page.dart'; | ||||||
|  | import 'package:lottie/lottie.dart'; | ||||||
|  | 
 | ||||||
|  | class SplashAnimationScreen extends StatefulWidget { | ||||||
|  |   final Widget? routeWidget; | ||||||
|  | 
 | ||||||
|  |   SplashAnimationScreen({super.key, this.routeWidget}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   _SplashAnimationScreenState createState() { | ||||||
|  |     return _SplashAnimationScreenState(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _SplashAnimationScreenState extends State<SplashAnimationScreen> with SingleTickerProviderStateMixin { | ||||||
|  |   late final AnimationController _controller; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     _controller = AnimationController(vsync: this); | ||||||
|  |     _controller.addListener(() { | ||||||
|  |       if (_controller.status == AnimationStatus.completed) { | ||||||
|  |         Navigator.of(context).pushReplacement(FadePage(page: widget.routeWidget ?? LoginScreen())); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _controller.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Scaffold( | ||||||
|  |       backgroundColor: AppColors.whiteColor, | ||||||
|  |       body: Stack( | ||||||
|  |         children: [ | ||||||
|  |           Lottie.asset(AppAnimations.splashLaunching, controller: _controller, onLoaded: (composition) { | ||||||
|  |             _controller | ||||||
|  |               ..duration = composition.duration | ||||||
|  |               ..forward(); // Start the animation | ||||||
|  |           }, repeat: false, reverse: false, frameRate: FrameRate(60), fit: BoxFit.fill) | ||||||
|  |               .center, | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // todo: do-not remove this code,as animation need to test on multiple screen sizes | ||||||
|  | 
 | ||||||
|  | class AnimatedScreen extends StatefulWidget { | ||||||
|  |   const AnimatedScreen({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   State<AnimatedScreen> createState() => _AnimatedScreenState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _AnimatedScreenState extends State<AnimatedScreen> with TickerProviderStateMixin { | ||||||
|  |   late AnimationController _moveController; | ||||||
|  |   late Animation<Offset> _positionAnimation; | ||||||
|  |   late AnimationController _expandController; | ||||||
|  |   late Animation<double> _expandAnimation; | ||||||
|  | 
 | ||||||
|  |   bool isRipple = false; | ||||||
|  |   late final AnimationController _controller; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     _controller = AnimationController(vsync: this); | ||||||
|  |     _controller.addListener(() { | ||||||
|  |       if (_controller.status == AnimationStatus.completed) { | ||||||
|  |         Navigator.of(context).pushReplacement( | ||||||
|  |           FadePage( | ||||||
|  |             page: LoginScreen(), | ||||||
|  |           ), | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     // Step 1: Move circle from bottom-left to top-right | ||||||
|  |     _moveController = AnimationController(vsync: this, duration: const Duration(seconds: 1)); | ||||||
|  |     _positionAnimation = Tween<Offset>( | ||||||
|  |       begin: const Offset(-1, 1), | ||||||
|  |       end: const Offset(1, -1), | ||||||
|  |     ).animate( | ||||||
|  |       CurvedAnimation(parent: _moveController, curve: const Cubic(0.82, -0.01, 0.58, 1)), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     // Step 2: Expand white circle from center | ||||||
|  |     _expandController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000)); | ||||||
|  |     _expandAnimation = Tween<double>( | ||||||
|  |       begin: 0.0, | ||||||
|  |       end: 4.0, | ||||||
|  |     ).animate(CurvedAnimation(parent: _expandController, curve: Curves.easeOut)); | ||||||
|  | 
 | ||||||
|  |     // Trigger the animations in sequence | ||||||
|  |     _moveController.forward().whenComplete(() { | ||||||
|  |       setState(() { | ||||||
|  |         isRipple = true; | ||||||
|  |       }); | ||||||
|  |       _expandController.forward().whenComplete(() { | ||||||
|  |         setState(() { | ||||||
|  |           isRipple = false; | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _controller.dispose(); | ||||||
|  |     _moveController.dispose(); | ||||||
|  |     _expandController.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     final screenSize = MediaQuery.of(context).size; | ||||||
|  | 
 | ||||||
|  |     return Scaffold( | ||||||
|  |       backgroundColor: AppColors.whiteColor, | ||||||
|  |       body: Stack( | ||||||
|  |         children: [ | ||||||
|  |           // Moving rotated ellipse | ||||||
|  | 
 | ||||||
|  |           Lottie.asset(AppAnimations.splashLaunching, controller: _controller, onLoaded: (composition) { | ||||||
|  |             _controller | ||||||
|  |               ..duration = composition.duration | ||||||
|  |               ..forward(); // Start the animation | ||||||
|  |           }, repeat: false, reverse: false, frameRate: FrameRate(60), fit: BoxFit.fill) | ||||||
|  |               .center, | ||||||
|  |           // Lottie.asset(AppAnimations.loadingAnimation, repeat: true, reverse: false, frameRate: FrameRate(60), width: 80.h, height: 80.h, fit: BoxFit.fill).center, | ||||||
|  |           // | ||||||
|  |           // AnimatedContainer( | ||||||
|  |           //   duration: Duration(milliseconds: 500), | ||||||
|  |           //   width: screenSize.width, | ||||||
|  |           //   height: screenSize.height, | ||||||
|  |           //   color: isRipple ? AppColors.primaryRedColor : AppColors.whiteColor, | ||||||
|  |           // ), | ||||||
|  |           // | ||||||
|  |           // AnimatedBuilder( | ||||||
|  |           //   animation: _moveController, | ||||||
|  |           //   builder: (context, child) { | ||||||
|  |           //     final pos = _positionAnimation.value; | ||||||
|  |           //     return Positioned( | ||||||
|  |           //       left: (screenSize.width * .75) * (pos.dx), | ||||||
|  |           //       top: (screenSize.height * 0.75) * (pos.dy), | ||||||
|  |           //       child: Transform.rotate( | ||||||
|  |           //         angle: -120 * 3.1415927 / 150, // convert degrees to radians | ||||||
|  |           //         child: Container( | ||||||
|  |           //           width: 400, | ||||||
|  |           //           height: 653, | ||||||
|  |           //           decoration: BoxDecoration( | ||||||
|  |           //             color: Color(0xffED1C2B), | ||||||
|  |           //             borderRadius: BorderRadius.circular(330), | ||||||
|  |           //           ), | ||||||
|  |           //         ), | ||||||
|  |           //       ), | ||||||
|  |           //     ); | ||||||
|  |           //   }, | ||||||
|  |           // ), | ||||||
|  |           // // Expanding white circle | ||||||
|  |           // AnimatedBuilder( | ||||||
|  |           //   animation: _expandController, | ||||||
|  |           //   builder: (context, child) { | ||||||
|  |           //     return Center( | ||||||
|  |           //       child: Transform.scale( | ||||||
|  |           //         scale: _expandAnimation.value, | ||||||
|  |           //         child: Opacity( | ||||||
|  |           //           opacity: 1.0, //- _expandAnimation.value.clamp(0.0, 1.0), | ||||||
|  |           //           child: Container( | ||||||
|  |           //               decoration: const BoxDecoration( | ||||||
|  |           //             color: Colors.white, | ||||||
|  |           //             shape: BoxShape.circle, | ||||||
|  |           //             // border: Border.fromBorderSide(BorderSide( | ||||||
|  |           //             //   width: 0, | ||||||
|  |           //             //   color: Color(0xffED1C2B), | ||||||
|  |           //             // ) | ||||||
|  |           //           )), | ||||||
|  |           //         ), | ||||||
|  |           //         // ), | ||||||
|  |           //       ), | ||||||
|  |           //     ); | ||||||
|  |           //   }, | ||||||
|  |           // ), | ||||||
|  |           // AnimatedBuilder( | ||||||
|  |           //   animation: _expandController, | ||||||
|  |           //   builder: (context, child) { | ||||||
|  |           //     final screenSize = MediaQuery.of(context).size; | ||||||
|  |           //     final maxDiameter = | ||||||
|  |           //         (screenSize.width > screenSize.height ? screenSize.width : screenSize.height) * 2; | ||||||
|  |           // | ||||||
|  |           //     return Center( | ||||||
|  |           //       child: Transform.scale( | ||||||
|  |           //         scale: _expandAnimation.value * maxDiameter / 100, // scale up to fill screen | ||||||
|  |           //         child: Opacity( | ||||||
|  |           //           opacity: (1.0 - _expandAnimation.value).clamp(0.0, 1.0), | ||||||
|  |           //           child: Container( | ||||||
|  |           //             decoration: const BoxDecoration( | ||||||
|  |           //               color: Colors.white, | ||||||
|  |           //               shape: BoxShape.circle, | ||||||
|  |           //             ), | ||||||
|  |           //           ), | ||||||
|  |           //         ), | ||||||
|  |           //       ), | ||||||
|  |           //     ); | ||||||
|  |           //   }, | ||||||
|  |           // ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class MoveObjectDemo extends StatefulWidget { | ||||||
|  |   const MoveObjectDemo({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   State<MoveObjectDemo> createState() => _MoveObjectDemoState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _MoveObjectDemoState extends State<MoveObjectDemo> with SingleTickerProviderStateMixin { | ||||||
|  |   late AnimationController _controller; | ||||||
|  |   late Animation<Alignment> _alignmentAnimation; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  | 
 | ||||||
|  |     _controller = AnimationController( | ||||||
|  |       vsync: this, | ||||||
|  |       duration: const Duration(seconds: 1), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     _alignmentAnimation = AlignmentTween( | ||||||
|  |       begin: Alignment(-2.0, 2.5), | ||||||
|  |       end: Alignment(2.5, -2), | ||||||
|  |     ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); | ||||||
|  | 
 | ||||||
|  |     _controller.forward(); // start animation | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _controller.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Scaffold( | ||||||
|  |       body: AnimatedBuilder( | ||||||
|  |         animation: _alignmentAnimation, | ||||||
|  |         builder: (context, child) { | ||||||
|  |           return Align( | ||||||
|  |             alignment: _alignmentAnimation.value, | ||||||
|  |             child: Transform.rotate( | ||||||
|  |               angle: -120 * 3.1415927 / 180, | ||||||
|  |               child: Container( | ||||||
|  |                 width: 200, | ||||||
|  |                 height: 375, | ||||||
|  |                 decoration: BoxDecoration( | ||||||
|  |                   color: const Color(0xffED1C2B), | ||||||
|  |                   borderRadius: BorderRadius.circular(330), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  | 
 | ||||||
|  |             // Transform.rotate( | ||||||
|  |             //   angle: -120 * 3.1415927 / 180, // convert to radians | ||||||
|  |             //   child: Container( | ||||||
|  |             //     width: 400, | ||||||
|  |             //     height: 653, | ||||||
|  |             //     decoration: BoxDecoration( | ||||||
|  |             //       color: const Color(0xffED1C2B), | ||||||
|  |             //       borderRadius: BorderRadius.circular(330), | ||||||
|  |             //     ), | ||||||
|  |             //   ), | ||||||
|  |             // ), | ||||||
|  |           ); | ||||||
|  |         }, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class MoveOnClickDemo extends StatefulWidget { | ||||||
|  |   const MoveOnClickDemo({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   State<MoveOnClickDemo> createState() => _MoveOnClickDemoState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _MoveOnClickDemoState extends State<MoveOnClickDemo> with TickerProviderStateMixin { | ||||||
|  |   late AnimationController _controller; | ||||||
|  |   late Animation<Alignment> _alignmentAnimation; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     init(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   init() { | ||||||
|  |     _controller = AnimationController( | ||||||
|  |       vsync: this, | ||||||
|  |       duration: const Duration(milliseconds: 1000), // Figma duration | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     _alignmentAnimation = AlignmentTween( | ||||||
|  |       // begin: Alignment(-10.0, 5), | ||||||
|  |       // end: Alignment(5, -2), | ||||||
|  |       begin: Alignment.bottomLeft, | ||||||
|  |       end: Alignment.topRight, | ||||||
|  |     ).animate(CurvedAnimation( | ||||||
|  |       parent: _controller, | ||||||
|  |       curve: const Cubic(0.82, -0.01, 0.58, 1), // Figma cubic-bezier | ||||||
|  |     )); | ||||||
|  |     _animate(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _controller.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   void _animate() { | ||||||
|  |     if (_controller.isCompleted) { | ||||||
|  |       _controller.reverse(); | ||||||
|  |     } else { | ||||||
|  |       _controller.forward(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Scaffold( | ||||||
|  |       body: GestureDetector( | ||||||
|  |         onTap: _animate, // trigger on click | ||||||
|  |         onDoubleTap: () { | ||||||
|  |           _controller.dispose(); | ||||||
|  |           init(); | ||||||
|  |         }, | ||||||
|  |         child: AnimatedBuilder( | ||||||
|  |           animation: _alignmentAnimation, | ||||||
|  |           builder: (context, child) { | ||||||
|  |             print(_alignmentAnimation.value); | ||||||
|  |             return Align( | ||||||
|  |               alignment: _alignmentAnimation.value, | ||||||
|  |               child: Transform.rotate( | ||||||
|  |                 angle: -120 * 3.1415927 / 145, // -120 deg | ||||||
|  |                 child: Container( | ||||||
|  |                   width: 100, | ||||||
|  |                   height: 150, | ||||||
|  |                   decoration: BoxDecoration( | ||||||
|  |                     color: const Color(0xffED1C2B), | ||||||
|  |                     borderRadius: BorderRadius.circular(330), | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |           }, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
					Loading…
					
					
				
		Reference in New Issue