Android Flutter在点击事件上添加动画效果实现全过程

 更新时间:2023年03月27日 09:33:08   作者:不入流Android开发  
这篇文章主要给大家介绍了关于Android Flutter在点击事件上添加动画效果实现的相关资料,通过实例代码介绍的非常详细,对大家学习Android具有一定的参考学习价值,需要的朋友可以参考下

在Android App的开发项目中,我们需要在点击事件上实现一个动画效果来提高用户的体验度。比如闲鱼底部中间按钮的那种。该怎么实现呢? 一起来看看吧

实现效果如图:

​实现思路

根据UI的设计图,对每个模块设计好动画效果,需要实现以下四个效果。

1、底部返回键旋转动画

底部返回按钮动画其实就是个旋转动画,利用Transform.rotate设置angle的值即可,这里使用了GetX来对angle进行动态控制。

//返回键旋转角度,初始旋转45度,使其初始样式为 +
var angle = (pi / 4).obs;
 
///关闭按钮旋转动画控制器
late final AnimationController closeController;
late final Animation<double> closeAnimation;
 
///返回键旋转动画
closeController = AnimationController(
  duration: const Duration(milliseconds: 300),
  vsync: provider,
);
 
///返回键旋转动画
closeController = AnimationController(
  duration: const Duration(milliseconds: 300),
  vsync: provider,
);
 
///页面渲染完才开始执行,不然第一次打开不会启动动画
WidgetsBinding.instance.addPostFrameCallback((duration) {
  closeAnimation =
      Tween(begin: pi / 4, end: pi / 2).animate(closeController)
        ..addListener(() {
          angle.value = closeAnimation.value;
        });
  closeController.forward();
});
 
 
///关闭按钮点击事件
void close() {
  ///反转动画,并关闭页面
  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、底部四个栏目变速上移动画+渐变动画

四个栏目其实就是个平移动画,只不过闲鱼是四个栏目一起平移,而我选择了变速平移,这样视觉效果上会好一点。

//透明度变化
List<AnimationController> opacityControllerList = [];
//上移动画,由于每个栏目的移动速度不一样,需要用List保存四个AnimationController,
//如果想像闲鱼那种整体上移,则只用一个AnimationController即可。
List<AnimationController> offsetControllerList = [];
List<Animation<Offset>> offsetAnimationList = [];
 
//之所以用addIf,是因为项目中这几个栏目的显示是动态显示的,这里就直接写成true
Column(
    children: []
      ..addIf(
          true,
          buildItem('assets/user/ic-train-nomal-car.webp',"学车加练","自主预约,快速拿证"))
      ..addIf(
          true,
          buildItem('assets/user/ic-train-fuuxn-car.webp',"有证复训","优质陪练,轻松驾车"))
      ..addIf(
          true,
          buildItem('assets/user/ic-train-jiaxun-car.webp',"模拟加训","考前加训,临考不惧"))
      ..addIf(
          true,
          buildItem('assets/user/ic-train-jiakao-car.webp',"驾考报名","快捷报名无门槛"))
      ..add(playWidget())
      ..addAll([
        17.space,
      ]),
   )
       
//仅仅是为了在offsetController全部初始化完后执行play()
Widget playWidget() {
  //执行动画
  play();
  return Container();
}
 
int i = 0;
 
Widget buildItem(String img,String tab,String slogan) {
  //由于底部栏目是动态显示的,需要在创建Widget时一同创建offsetController和offsetAnimation
  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)),
  );
}
 
//执行动画
void play() async {
  for (int i = 0; i < offsetControllerList.length; i++) {
    opacityControllerList[i].forward();
 
    ///栏目正序依次延迟(40 + 2 * i) * i的时间,曲线速率
    Future.delayed(Duration(milliseconds: (40 + 2 * i) * i), () {
      offsetControllerList[i]
          .forward()
          .whenComplete(() => offsetControllerList[i].stop());
    });
  }
}
 
///关闭按钮点击事件
void close() {
  ///反转动画,并关闭页面
  Future.delayed(
     const Duration(milliseconds: 120), () {
    Get.back();
  });
 
  for (int i = offsetControllerList.length - 1; i >= 0; i--) {
    ///栏目倒叙依次延迟(40 + 2 * (offsetControllerList.length-1-i)) * (offsetControllerList.length-1-i))的时间
    Future.delayed(
        Duration(
            milliseconds:
            (40 + 2 * (offsetControllerList.length-1-i)) * (offsetControllerList.length-1-i)), () {
      offsetControllerList[i].reverse();
    });
  }
  opacityTopController.reverse();
}

3、中间图片渐变动画

渐变动画使用FadeTransition即可。

///图片透明度渐变动画控制器
late final AnimationController imgController;
 
///图片透明度渐变动画
imgController = AnimationController(
    duration: const Duration(milliseconds: 500),
    lowerBound: 0.0,
    upperBound: 1.0,
    vsync: provider);
imgController.forward().whenComplete(() => imgController.stop());
 
///渐变过渡
FadeTransition(
  opacity: imgController,
  child:
  Image.asset("assets/user/ic-traincar-guide.webp"),
),
 
///关闭按钮点击事件
void close() {
  imgController.reverse();
}

4、顶部文案渐变动画+下移动画

///顶部标题下移动画控制器
late final AnimationController offsetTopController;
late final Animation<Offset> offsetTopAnimation;
 
///顶部标题渐变动画控制器
late final AnimationController opacityTopController;
 
 
///顶部标题上移动画
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(
              '练车指南',
              style: TextStyle(
                color: Color(0XFF141414),
                fontSize: 32,
                fontWeight: FontWeight.w800,
              ),
            ),
            2.space,
            const Text('易练只为您提供优质教练,为您的安全保驾护航',
                style: TextStyle(
                    color: Color(0XFF141414),
                    fontSize: 15)),
          ],
        ))),
         
 
///关闭按钮点击事件
void close() {
  offsetTopController.reverse();
  opacityTopController.reverse();
 
}

5、注销动画

最后,在关闭页面的时候不要忘记注销动画。

///关闭时注销动画
void dispose() {
  for (int i = offsetControllerList.length - 1; i > 0; i--) {
    offsetControllerList[i].dispose();
  }
  offsetTopController.dispose();
  opacityTopController.dispose();
  imgController.dispose();
  closeController.dispose();
}

以上就是Android Flutter实现仿闲鱼动画效果的详细内容,更多关于Android Flutter知识可以参考

Android Futtter学习文档​

总结

到此这篇关于Android Flutter在点击事件上添加动画效果的文章就介绍到这了,更多相关Android Flutter点击事件动画效果内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Android异步消息机制详解

    Android异步消息机制详解

    这篇文章主要为大家详细介绍了Android异步消息机制的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • Android自定义商品购买数量加减控件

    Android自定义商品购买数量加减控件

    这篇文章主要为大家详细介绍了Android自定义商品购买数量加减控件的相关代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • Android状态栏的适配汇总

    Android状态栏的适配汇总

    这篇文章主要给大家介绍了关于Android状态栏适配的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-05-05
  • Android自定义View绘制彩色圆弧

    Android自定义View绘制彩色圆弧

    这篇文章主要为大家详细介绍了Android自定义View绘制彩色圆弧,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • Android如何快速适配暗黑模式详解

    Android如何快速适配暗黑模式详解

    微信在前段时间的更新中也实现了暗黑模式,而苹果系统也早就支持暗黑模式,Android也一样可以实现,下面这篇文章主要给大家介绍了关于Android如何快速适配暗黑模式的相关资料,需要的朋友可以参考下
    2021-08-08
  • Android中实时获取音量分贝值详解

    Android中实时获取音量分贝值详解

    这篇文章主要介绍了Android中实时获取音量分贝值详解,本文讲解了基础知识、Android API、MediaRecorder、AudioRecord等内容,需要的朋友可以参考下
    2015-04-04
  • 开箱即用的Google与百度定位坐标系转换实例

    开箱即用的Google与百度定位坐标系转换实例

    这篇文章主要为大家介绍了开箱即用的Google与百度定位坐标系转换实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 自定义TextView跑马灯效果可控制启动/停止/速度/焦点

    自定义TextView跑马灯效果可控制启动/停止/速度/焦点

    Android自带的跑马灯效果不太好控制,不能控制速度,不能即时停止和启动,而且还受焦点的影响蛋疼不已。由于项目需求需所以自己写了一个自定义的TextView,感兴趣的朋友可以了解下
    2013-01-01
  • Android RecyclerView滑动删除和拖动排序

    Android RecyclerView滑动删除和拖动排序

    这篇文章主要介绍了Android RecyclerView滑动删除和拖动排序的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • 分享五种Android常用布局方式

    分享五种Android常用布局方式

    Android布局是应用界面开发的重要一环,在Android中,共有五种布局方式,分别是:FrameLayout(框架布 局),LinearLayout (线性布局),AbsoluteLayout(绝对布局),RelativeLayout(相对布局),TableLayout(表格布局),小编通过本文逐一给大家详解
    2015-11-11

最新评论