欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?Flutter在點(diǎn)擊事件上添加動(dòng)畫效果實(shí)現(xiàn)全過程

 更新時(shí)間:2023年03月27日 09:33:08   作者:不入流Android開發(fā)  
這篇文章主要給大家介紹了關(guān)于Android?Flutter在點(diǎn)擊事件上添加動(dòng)畫效果實(shí)現(xiàn)的相關(guān)資料,通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)Android具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

在Android App的開發(fā)項(xiàng)目中,我們需要在點(diǎn)擊事件上實(shí)現(xiàn)一個(gè)動(dòng)畫效果來提高用戶的體驗(yàn)度。比如閑魚底部中間按鈕的那種。該怎么實(shí)現(xiàn)呢? 一起來看看吧

實(shí)現(xiàn)效果如圖:

?實(shí)現(xiàn)思路

根據(jù)UI的設(shè)計(jì)圖,對(duì)每個(gè)模塊設(shè)計(jì)好動(dòng)畫效果,需要實(shí)現(xiàn)以下四個(gè)效果。

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

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

//返回鍵旋轉(zhuǎn)角度,初始旋轉(zhuǎn)45度,使其初始樣式為 +
var angle = (pi / 4).obs;
 
///關(guān)閉按鈕旋轉(zhuǎn)動(dòng)畫控制器
late final AnimationController closeController;
late final Animation<double> closeAnimation;
 
///返回鍵旋轉(zhuǎn)動(dòng)畫
closeController = AnimationController(
  duration: const Duration(milliseconds: 300),
  vsync: provider,
);
 
///返回鍵旋轉(zhuǎn)動(dòng)畫
closeController = AnimationController(
  duration: const Duration(milliseconds: 300),
  vsync: provider,
);
 
///頁面渲染完才開始執(zhí)行,不然第一次打開不會(huì)啟動(dòng)動(dòng)畫
WidgetsBinding.instance.addPostFrameCallback((duration) {
  closeAnimation =
      Tween(begin: pi / 4, end: pi / 2).animate(closeController)
        ..addListener(() {
          angle.value = closeAnimation.value;
        });
  closeController.forward();
});
 
 
///關(guān)閉按鈕點(diǎn)擊事件
void close() {
  ///反轉(zhuǎn)動(dòng)畫,并關(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、底部四個(gè)欄目變速上移動(dòng)畫+漸變動(dòng)畫

四個(gè)欄目其實(shí)就是個(gè)平移動(dòng)畫,只不過閑魚是四個(gè)欄目一起平移,而我選擇了變速平移,這樣視覺效果上會(huì)好一點(diǎn)。

//透明度變化
List<AnimationController> opacityControllerList = [];
//上移動(dòng)畫,由于每個(gè)欄目的移動(dòng)速度不一樣,需要用List保存四個(gè)AnimationController,
//如果想像閑魚那種整體上移,則只用一個(gè)AnimationController即可。
List<AnimationController> offsetControllerList = [];
List<Animation<Offset>> offsetAnimationList = [];
 
//之所以用addIf,是因?yàn)轫?xiàng)目中這幾個(gè)欄目的顯示是動(dòng)態(tài)顯示的,這里就直接寫成true
Column(
    children: []
      ..addIf(
          true,
          buildItem('assets/user/ic-train-nomal-car.webp',"學(xué)車加練","自主預(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',"駕考報(bào)名","快捷報(bào)名無門檻"))
      ..add(playWidget())
      ..addAll([
        17.space,
      ]),
   )
       
//僅僅是為了在offsetController全部初始化完后執(zhí)行play()
Widget playWidget() {
  //執(zhí)行動(dòng)畫
  play();
  return Container();
}
 
int i = 0;
 
Widget buildItem(String img,String tab,String slogan) {
  //由于底部欄目是動(dòng)態(tài)顯示的,需要在創(chuàng)建Widget時(shí)一同創(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í)行動(dòng)畫
void play() async {
  for (int i = 0; i < offsetControllerList.length; i++) {
    opacityControllerList[i].forward();
 
    ///欄目正序依次延遲(40 + 2 * i) * i的時(shí)間,曲線速率
    Future.delayed(Duration(milliseconds: (40 + 2 * i) * i), () {
      offsetControllerList[i]
          .forward()
          .whenComplete(() => offsetControllerList[i].stop());
    });
  }
}
 
///關(guān)閉按鈕點(diǎn)擊事件
void close() {
  ///反轉(zhuǎn)動(dòng)畫,并關(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))的時(shí)間
    Future.delayed(
        Duration(
            milliseconds:
            (40 + 2 * (offsetControllerList.length-1-i)) * (offsetControllerList.length-1-i)), () {
      offsetControllerList[i].reverse();
    });
  }
  opacityTopController.reverse();
}

3、中間圖片漸變動(dòng)畫

漸變動(dòng)畫使用FadeTransition即可。

///圖片透明度漸變動(dòng)畫控制器
late final AnimationController imgController;
 
///圖片透明度漸變動(dòng)畫
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)閉按鈕點(diǎn)擊事件
void close() {
  imgController.reverse();
}

4、頂部文案漸變動(dòng)畫+下移動(dòng)畫

///頂部標(biāo)題下移動(dòng)畫控制器
late final AnimationController offsetTopController;
late final Animation<Offset> offsetTopAnimation;
 
///頂部標(biāo)題漸變動(dòng)畫控制器
late final AnimationController opacityTopController;
 
 
///頂部標(biāo)題上移動(dòng)畫
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ì)教練,為您的安全保駕護(hù)航',
                style: TextStyle(
                    color: Color(0XFF141414),
                    fontSize: 15)),
          ],
        ))),
         
 
///關(guān)閉按鈕點(diǎn)擊事件
void close() {
  offsetTopController.reverse();
  opacityTopController.reverse();
 
}

5、注銷動(dòng)畫

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

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

以上就是Android Flutter實(shí)現(xiàn)仿閑魚動(dòng)畫效果的詳細(xì)內(nèi)容,更多關(guān)于Android Flutter知識(shí)可以參考

Android Futtter學(xué)習(xí)文檔?

總結(jié)

到此這篇關(guān)于Android Flutter在點(diǎn)擊事件上添加動(dòng)畫效果的文章就介紹到這了,更多相關(guān)Android Flutter點(diǎn)擊事件動(dòng)畫效果內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android異步消息機(jī)制詳解

    Android異步消息機(jī)制詳解

    這篇文章主要為大家詳細(xì)介紹了Android異步消息機(jī)制的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android自定義商品購買數(shù)量加減控件

    Android自定義商品購買數(shù)量加減控件

    這篇文章主要為大家詳細(xì)介紹了Android自定義商品購買數(shù)量加減控件的相關(guān)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Android狀態(tài)欄的適配匯總

    Android狀態(tài)欄的適配匯總

    這篇文章主要給大家介紹了關(guān)于Android狀態(tài)欄適配的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Android自定義View繪制彩色圓弧

    Android自定義View繪制彩色圓弧

    這篇文章主要為大家詳細(xì)介紹了Android自定義View繪制彩色圓弧,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • Android如何快速適配暗黑模式詳解

    Android如何快速適配暗黑模式詳解

    微信在前段時(shí)間的更新中也實(shí)現(xiàn)了暗黑模式,而蘋果系統(tǒng)也早就支持暗黑模式,Android也一樣可以實(shí)現(xiàn),下面這篇文章主要給大家介紹了關(guān)于Android如何快速適配暗黑模式的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Android中實(shí)時(shí)獲取音量分貝值詳解

    Android中實(shí)時(shí)獲取音量分貝值詳解

    這篇文章主要介紹了Android中實(shí)時(shí)獲取音量分貝值詳解,本文講解了基礎(chǔ)知識(shí)、Android API、MediaRecorder、AudioRecord等內(nèi)容,需要的朋友可以參考下
    2015-04-04
  • 開箱即用的Google與百度定位坐標(biāo)系轉(zhuǎn)換實(shí)例

    開箱即用的Google與百度定位坐標(biāo)系轉(zhuǎn)換實(shí)例

    這篇文章主要為大家介紹了開箱即用的Google與百度定位坐標(biāo)系轉(zhuǎn)換實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 自定義TextView跑馬燈效果可控制啟動(dòng)/停止/速度/焦點(diǎn)

    自定義TextView跑馬燈效果可控制啟動(dòng)/停止/速度/焦點(diǎn)

    Android自帶的跑馬燈效果不太好控制,不能控制速度,不能即時(shí)停止和啟動(dòng),而且還受焦點(diǎn)的影響蛋疼不已。由于項(xiàng)目需求需所以自己寫了一個(gè)自定義的TextView,感興趣的朋友可以了解下
    2013-01-01
  • Android RecyclerView滑動(dòng)刪除和拖動(dòng)排序

    Android RecyclerView滑動(dòng)刪除和拖動(dòng)排序

    這篇文章主要介紹了Android RecyclerView滑動(dòng)刪除和拖動(dòng)排序的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 分享五種Android常用布局方式

    分享五種Android常用布局方式

    Android布局是應(yīng)用界面開發(fā)的重要一環(huán),在Android中,共有五種布局方式,分別是:FrameLayout(框架布 局),LinearLayout (線性布局),AbsoluteLayout(絕對(duì)布局),RelativeLayout(相對(duì)布局),TableLayout(表格布局),小編通過本文逐一給大家詳解
    2015-11-11

最新評(píng)論