最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android Flutter實現(xiàn)仿閑魚動畫效果

 更新時間:2023年02月23日 10:56:35   作者:天選的打工人  
目前正在做的項目,為了增加用戶的體驗度,準備增加一些動畫效果。本文將通過Android Flutter實現(xiàn)仿閑魚動畫效果,感興趣的可以嘗試一下

前言

目前正在做的項目,為了增加用戶的體驗度,準備增加一些動畫效果,其中底部欄中間按鈕的點擊事件參考了閑魚的動效,便在此基礎(chǔ)上仿寫了該動效,并增加了一些新的效果。

動效

閑魚動效

仿寫效果

思路

根據(jù)UI的設(shè)計圖,對每個模塊設(shè)計好動畫效果,本人主要設(shè)計了以下四個效果。

1、底部返回鍵旋轉(zhuǎn)動畫

底部返回按鈕動畫其實就是個旋轉(zhuǎn)動畫,利用Transform.rotate設(shè)置angle的值即可,這里使用了GetX來對angle進行動態(tài)控制。

//返回鍵旋轉(zhuǎn)角度,初始旋轉(zhuǎn)45度,使其初始樣式為 +
var angle = (pi / 4).obs;

///關(guān)閉按鈕旋轉(zhuǎn)動畫控制器
late final AnimationController closeController;
late final Animation<double> closeAnimation;

///返回鍵旋轉(zhuǎn)動畫
closeController = AnimationController(
  duration: const Duration(milliseconds: 300),
  vsync: provider,
);

///返回鍵旋轉(zhuǎn)動畫
closeController = AnimationController(
  duration: const Duration(milliseconds: 300),
  vsync: provider,
);

///頁面渲染完才開始執(zhí)行,不然第一次打開不會啟動動畫
WidgetsBinding.instance.addPostFrameCallback((duration) {
  closeAnimation =
      Tween(begin: pi / 4, end: pi / 2).animate(closeController)
        ..addListener(() {
          angle.value = closeAnimation.value;
        });
  closeController.forward();
});


///關(guān)閉按鈕點擊事件
void close() {
  ///反轉(zhuǎn)動畫,并關(guān)閉頁面
  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,是因為項目中這幾個欄目的顯示是動態(tài)顯示的,這里就直接寫成true
Column(
    children: []
      ..addIf(
          true,
          buildItem('assets/user/ic-train-nomal-car.webp',"學車加練","自主預(yù)約,快速拿證"))
      ..addIf(
          true,
          buildItem('assets/user/ic-train-fuuxn-car.webp',"有證復(fù)訓(xùn)","優(yōu)質(zhì)陪練,輕松駕車"))
      ..addIf(
          true,
          buildItem('assets/user/ic-train-jiaxun-car.webp',"模擬加訓(xùn)","考前加訓(xùn),臨考不懼"))
      ..addIf(
          true,
          buildItem('assets/user/ic-train-jiakao-car.webp',"駕考報名","快捷報名無門檻"))
      ..add(playWidget())
      ..addAll([
        17.space,
      ]),
   )
      
//僅僅是為了在offsetController全部初始化完后執(zhí)行play()
Widget playWidget() {
  //執(zhí)行動畫
  play();
  return Container();
}

int i = 0;

Widget buildItem(String img,String tab,String slogan) {
  //由于底部欄目是動態(tài)顯示的,需要在創(chuàng)建Widget時一同創(chuàng)建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)),
  );
}

//執(zhí)行動畫
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());
    });
  }
}



///關(guān)閉按鈕點擊事件
void close() {
  ///反轉(zhuǎn)動畫,并關(guān)閉頁面
  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"),
),

///關(guān)閉按鈕點擊事件
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('易練只為您提供優(yōu)質(zhì)教練,為您的安全保駕護航',
                style: TextStyle(
                    color: Color(0XFF141414),
                    fontSize: 15)),
          ],
        ))),
        

///關(guān)閉按鈕點擊事件
void close() {
  offsetTopController.reverse();
  opacityTopController.reverse();

}

5、注銷動畫

最后,在關(guān)閉頁面的時候不要忘記注銷動畫。

///關(guān)閉時注銷動畫
void dispose() {
  for (int i = offsetControllerList.length - 1; i > 0; i--) {
    offsetControllerList[i].dispose();
  }
  offsetTopController.dispose();
  opacityTopController.dispose();
  imgController.dispose();
  closeController.dispose();
}

以上就是Android Flutter實現(xiàn)仿閑魚動畫效果的詳細內(nèi)容,更多關(guān)于Android Flutter仿閑魚動畫的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android Tiny集成圖片壓縮框架的使用

    Android Tiny集成圖片壓縮框架的使用

    本篇文章主要介紹了Android Tiny集成圖片壓縮框架的使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • android imageview圖片居中技巧應(yīng)用

    android imageview圖片居中技巧應(yīng)用

    做UI布局,尤其是遇到比較復(fù)雜的多重LinearLayout嵌套,常常會被一些比較小的問題困擾上半天,可是無論怎樣設(shè)置layout_gravity屬性,都無法達到效果
    2012-11-11
  • ViewPager 與 Fragment相結(jié)合實現(xiàn)微信界面實例代碼

    ViewPager 與 Fragment相結(jié)合實現(xiàn)微信界面實例代碼

    這篇文章主要介紹了ViewPager 與 Fragment相結(jié)合實現(xiàn)微信界面實例代碼的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • Android 開啟閃光燈做手電筒的詳解

    Android 開啟閃光燈做手電筒的詳解

    本篇文章是對Android中開啟閃光燈做手電筒的方法進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • Android編程之Button控件用法實例分析

    Android編程之Button控件用法實例分析

    這篇文章主要介紹了Android編程之Button控件用法,較為詳細的分析了Button控件的功能、定義及相關(guān)使用注意事項,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-10-10
  • Android操作SQLite基本用法

    Android操作SQLite基本用法

    這篇文章主要介紹了Android操作SQLite基本用法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-12-12
  • Android 詳解自定義圓角輸入框和按鈕的實現(xiàn)流程

    Android 詳解自定義圓角輸入框和按鈕的實現(xiàn)流程

    對于安卓程序員來說,自定義view簡直不要太重要,畢竟有很多功能,譬如圓形頭像這些,用單純的原生非常難以實現(xiàn),而用自定義view,簡直分分鐘,今天我們來實現(xiàn)自定義圓角輸入框和按鈕,大家可以跟著練習,掌握技巧
    2021-11-11
  • Android中獲取設(shè)備的各種信息總結(jié)

    Android中獲取設(shè)備的各種信息總結(jié)

    相信各位Android的開發(fā)者們都知道,現(xiàn)在幾乎所有的app都需要獲得設(shè)備信息,那么下面這篇文章就來詳細說說獲取設(shè)備信息的方法。
    2016-09-09
  • Android進階事件分發(fā)機制解決事件沖突

    Android進階事件分發(fā)機制解決事件沖突

    這篇文章主要為大家介紹了Android進階事件分發(fā)機制解決事件沖突過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01
  • Android自定義View實現(xiàn)心形圖案

    Android自定義View實現(xiàn)心形圖案

    這篇文章主要為大家詳細介紹了Android自定義View實現(xiàn)心形圖案,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評論

桐城市| 运城市| 宜州市| 通渭县| 丹巴县| 曲麻莱县| 巴里| 福建省| 全南县| 建昌县| 秀山| 富阳市| 东城区| 钦州市| 周宁县| 馆陶县| 吉首市| 棋牌| 铜梁县| 锡林郭勒盟| 巴彦县| 玛沁县| 金湖县| 夏津县| 分宜县| 曲阜市| 肥西县| 合肥市| 潼关县| 图木舒克市| 察雅县| 林西县| 阜宁县| 大庆市| 元谋县| 桃江县| 江北区| 永寿县| 泸水县| 桑植县| 梁河县|