Android Flutter adds animation effects on click events

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?