In the Android App development project, we need to implement an animation effect on the click event to improve the user experience. For example, the one with the middle button at the bottom of Xianyu. How to achieve it? Let’s take a look together
The realization effect is as shown in the figure:
?Implementation idea
According to the UI design drawing, to design animation effects for each module, the following four effects need to be achieved.
1. Bottom back key rotation animation
The back button animation at the bottom is actually a rotation animation. Just use Transform.rotate to set the value of the angle. Here, GetX is used to dynamically control the angle.
//Return the key rotation angle, the initial rotation is 45 degrees, so that the initial style is + var angle = (pi / 4).obs; ///Close button rotation animation controller late final AnimationController closeController; late final Animation<double> closeAnimation; ///Back key rotation animation closeController = AnimationController( duration: const Duration(milliseconds: 300), vsync: provider, ); ///Back key rotation animation closeController = AnimationController( duration: const Duration(milliseconds: 300), vsync: provider, ); ///After the page is rendered, the execution will start, otherwise the animation will not start when it is opened for the first time WidgetsBinding.instance.addPostFrameCallback((duration) { closeAnimation = Tween(begin: pi / 4, end: pi / 2).animate(closeController) ..addListener(() { angle.value = closeAnimation.value; }); closeController. forward(); }); ///Close button click event void close() { ///Reverse the animation and close the page Future. delayed( const Duration(milliseconds: 120), () { Get.back(); }); closeController. reverse(); } IconButton( onPressed: null, alignment: Alignment. center, icon: Transform. rotate( angle: controller. angle. value, child: SvgPicture.asset( "assets/user/ic-train-car-close.svg", width: 18, height: 18, color: Colors. black, ), ))
2. The four columns at the bottom change speed and move up animation + gradient animation
The four columns are actually a panning animation, but Xianyu pans the four columns together, and I chose variable speed panning, so the visual effect will be better.
//transparency change List<AnimationController> opacityControllerList = []; //Move up the animation, because the moving speed of each column is different, you need to save four AnimationControllers with List, //If you want to move up as a whole like Xianyu, you only need one AnimationController. List<AnimationController> offsetControllerList = []; List<Animation<Offset>> offsetAnimationList = []; //The reason why addIf is used is because the display of these columns in the project is dynamically displayed, so it is directly written as true here Column( children: [] ..addIf( true, buildItem('assets/user/ic-train-nomal-car.webp',"Learn to drive plus practice","Self-serve appointment, get certificate quickly")) ..addIf( true, buildItem('assets/user/ic-train-fuuxn-car.webp',"Certified retraining","Quality training, easy driving")) ..addIf( true, buildItem('assets/user/ic-train-jiaxun-car.webp',"Simulated additional training","Additional training before the exam, no fear before the exam")) ..addIf( true, buildItem('assets/user/ic-train-jiakao-car.webp',"Driving test registration","Quick registration without threshold")) ..add(playWidget()) ..addAll([ 17. space, ]), ) //Just to execute play() after offsetController is fully initialized Widget playWidget() { // execute the animation play(); return Container(); } int i = 0; Widget buildItem(String img,String tab,String slogan) { //Because the bottom column is displayed dynamically, you need to create offsetController and offsetAnimation together when creating the Widget i + + ; AnimationController offsetController = AnimationController( duration: Duration(milliseconds: 100 + i * 20), vsync: this, ); Animation<Offset> offsetAnimation = Tween<Offset>( begin: const Offset(0, 2.5), end: const Offset(0, 0), ).animate(CurvedAnimation( parent: offsetController, // curve: Curves. easeInOutSine, curve: const Cubic(0.12, 0.28, 0.48, 1), )); AnimationController opacityController = AnimationController( duration: const Duration(milliseconds: 500), lowerBound: 0.2, upperBound: 1.0, vsync: this); opacityControllerList.add(opacityController); offsetControllerList.add(offsetController); offsetAnimationList.add(offsetAnimation); return SlideTransition( position: offsetAnimation, child: FadeTransition( opacity: opacityController, child: Container( margin: EdgeInsets. only(bottom: 16), height: 62, decoration: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(12)), color: const Color(0xfffafafa)), child: Row(mainAxisAlignment: MainAxisAlignment. center, children: [ 24. space, Image.asset(img, width: 44, height: 44), 12. space, Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text(tab, style: const TextStyle( color: Color(0XFF000000), fontSize: 16, fontWeight: FontWeight. bold)), Text(slogan, style: const TextStyle( color: Color(0XFF6e6e6e), fontSize: 12)), ]). expanded, Image.asset("assets/user/ic-train-arrow.webp", width: 44, height: 44), 17. space ])).inkWell( onTap: () {}, delayMilliseconds: 50)), ); } // execute the animation void play() async { for (int i = 0; i < offsetControllerList. length; i ++ ) { opacityControllerList[i].forward(); ///Columns are sequentially delayed by (40 + 2 * i) * i time, curve speed Future. delayed(Duration(milliseconds: (40 + 2 * i) * i), () { offsetControllerList[i] .forward() .whenComplete(() => offsetControllerList[i].stop()); }); } } ///Close button click event void close() { ///Reverse the animation and close the page Future. delayed( const Duration(milliseconds: 120), () { Get.back(); }); for (int i = offsetControllerList. length - 1; i >= 0; i--) { ///Column flashbacks are delayed by (40 + 2 * (offsetControllerList.length-1-i)) * (offsetControllerList.length-1-i)) time Future. delayed( Duration( milliseconds: (40 + 2 * (offsetControllerList. length-1-i)) * (offsetControllerList. length-1-i)), () { offsetControllerList[i].reverse(); }); } opacityTopController. reverse(); }
3. Middle image gradient animation
Gradient animation can use FadeTransition.
///Image transparency gradient animation controller late final AnimationController imgController; ///Image transparency gradient animation imgController = AnimationController( duration: const Duration(milliseconds: 500), lowerBound: 0.0, upperBound: 1.0, vsync: provider); imgController.forward().whenComplete(() => imgController.stop()); /// Gradient transition FadeTransition( opacity: imgController, child: Image.asset("assets/user/ic-traincar-guide.webp"), ), ///Close button click event void close() { imgController. reverse(); }
4. Top copy gradient animation + down animation
///top title down animation controller late final AnimationController offsetTopController; late final Animation<Offset> offsetTopAnimation; ///Top title gradient animation controller late final AnimationController opacityTopController; ///The top title moves up the animation offsetTopController = AnimationController( duration: const Duration(milliseconds: 300), vsync: provider, ); offsetTopController .forward() .whenComplete(() => offsetTopController. stop()); offsetTopAnimation = Tween<Offset>( begin: const Offset(0, -0.8), end: const Offset(0, 0), ).animate(CurvedAnimation( parent: offsetTopController, curve: Curves. easeInOutCubic, )); offsetTopController .forward() .whenComplete(() => offsetTopController. stop()); //UI SlideTransition( position: offsetTopAnimation, child: FadeTransition( opacity: opacityTopController, child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ 80. space, const Text( 'Training Guide', style: TextStyle( color: Color(0XFF141414), fontSize: 32, fontWeight: FontWeight.w800, ), ), 2. space, const Text('Easy Training only provides you with high-quality coaches to protect your safety', style: TextStyle( color: Color(0XFF141414), fontSize: 15)), ], ))), ///Close button click event void close() { offsetTopController. reverse(); opacityTopController. reverse(); }
5. Logout animation
Finally, don’t forget the logout animation when closing the page.
///Logout animation when closing void dispose() { for (int i = offsetControllerList. length - 1; i > 0; i--) { offsetControllerList[i].dispose(); } offsetTopController.dispose(); opacityTopController.dispose(); imgController. dispose(); closeController. dispose(); }
The above is the detailed content of Android Flutter to realize the animation effect of imitating idle fish. For more knowledge about Android Flutter, please refer to
Android Futtter learning documentation?