Flutter實(shí)現(xiàn)動(dòng)畫(huà)卡片式Tab導(dǎo)航

前言

本人接觸Flutter不到一個(gè)月,深深感受到了這個(gè)平臺(tái)的威力,于是不斷學(xué)習(xí),F(xiàn)lutter官方Example中的flutter_gallery有一個(gè)非常好看的動(dòng)畫(huà)卡片式的Tab導(dǎo)航,很好的展示了Flutter各個(gè)widget的功能

其中的animation內(nèi)容,展示的是一個(gè)帶有動(dòng)畫(huà)和拖拽功能的 可展開(kāi)的卡片式Tab導(dǎo)航,非常漂亮,但是其實(shí)現(xiàn)沒(méi)有抽象出一個(gè)可供第三方使用的Widget出來(lái),而且其頁(yè)面內(nèi)容的定制性不夠友好,滑動(dòng)的時(shí)候也有bug,我在他的基礎(chǔ)上進(jìn)行了優(yōu)化

官方展示了一個(gè)非常好的開(kāi)源示例,我改造了一下,也不敢獨(dú)自享用,現(xiàn)在分享給大家,歡迎大家多多交流

外觀(guān)

實(shí)現(xiàn)

這里是我的代碼: GitHub/Realank

想使用這個(gè)控件非常簡(jiǎn)單,首先定義頁(yè)面數(shù)據(jù):

const Color _mariner = const Color(0xFF3B5F8F);
const Color _mediumPurple = const Color(0xFF8266D4);
const Color _tomato = const Color(0xFFF95B57);
const Color _mySin = const Color(0xFFF3A646);

List<CardSection> allSections = <CardSection>[
  new CardSection(
      title: 'First Page',
      leftColor: _mediumPurple,
      rightColor: _mariner,
      contentWidget: Center(child: new Text('第一頁(yè)'))),
  new CardSection(
      title: 'Second Page',
      leftColor: _mariner,
      rightColor: _mySin,
      contentWidget: Center(child: new Text('第二頁(yè)'))),
  new CardSection(
      title: 'Third Page',
      leftColor: _mySin,
      rightColor: _tomato,
      contentWidget: Center(child: new Text('第三頁(yè)'))),
  new CardSection(
      title: 'Forth Page',
      leftColor: _tomato,
      rightColor: Colors.blue,
      contentWidget: Center(child: new Text('第四頁(yè)'))),
  new CardSection(
      title: 'Fifth Page',
      leftColor: Colors.blue,
      rightColor: _mediumPurple,
      contentWidget: Center(child: new Text('第五頁(yè)'))),
];

然后創(chuàng)建這個(gè)控件:

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new Scaffold(
        body: Center(
          child: new AnimateTabNavigation(
            sectionList: allSections,
          ),
        ),
      ),
    );
  }
}

大功告成

原理

知其然還要知其所以然,下面來(lái)說(shuō)說(shuō)這個(gè)控件的實(shí)現(xiàn)原理

首先,在sections.dart里定義了數(shù)據(jù)結(jié)構(gòu):


class CardSection {
  CardSection({this.title, this.leftColor, this.rightColor, this.contentWidget});

  final String title;
  final Color leftColor;
  final Color rightColor;
  final Widget contentWidget;

  @override
  bool operator ==(Object other) {
    if (other is! CardSection) return false;
    final CardSection otherSection = other;
    return title == otherSection.title;
  }

  @override
  int get hashCode => title.hashCode;
}

它定義了其中一個(gè)卡片的標(biāo)題,左邊顏色和右邊顏色(為了顯示過(guò)渡顏色效果),以及子控件(這個(gè)是我改進(jìn)的,這樣可以別人使用的時(shí)候隨意添加控件)

然后在widgets.dart中定義了幾個(gè)widget:

  • SectionCard : 標(biāo)題卡片
  • SectionTitle : 標(biāo)題
  • SectionIndicator : 標(biāo)題下的裝飾線(xiàn)

最后在cardNavigation.dart中就是布局這些內(nèi)容啦,這里面代碼很復(fù)雜,其思路倒是不難:

  1. 定義全屏展示tab的高度maxHeight,以及打開(kāi)tab后,tab顯示在頂部的高度minHeight
  2. 在用戶(hù)拖動(dòng)tab卡片的時(shí)候,根據(jù)卡片的位置于minHeight和maxHeight的比例,計(jì)算出動(dòng)畫(huà)進(jìn)度(0.0-1.0)
  3. 在_AllSectionsLayout中,定義了全屏顯示tab時(shí),卡片的columnCardRect,以及打開(kāi)tab后,tab顯示在頂部時(shí)候的rowCardRectt
  4. 計(jì)算出這兩個(gè)rect在動(dòng)畫(huà)進(jìn)度0-1過(guò)程中的中間態(tài)的rect尺寸,賦值給每一個(gè)卡片,這樣卡片就有中間狀態(tài)的外觀(guān)了。
  5. 當(dāng)用戶(hù)點(diǎn)擊了tab區(qū)域,就會(huì)觸發(fā)_maybeScroll方法,這個(gè)方法判斷當(dāng)前的tab是全屏的還是打開(kāi)后的
  6. 當(dāng)tab是全屏的,就展開(kāi)對(duì)應(yīng)的tab頁(yè)
  7. 當(dāng)tab已經(jīng)是打開(kāi)的,就判斷點(diǎn)擊的位置,在tab欄的左側(cè),就往左翻頁(yè),反之亦然。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過(guò)CocoaPods安裝項(xiàng)目名稱(chēng)項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明AI閱讀 16,171評(píng)論 3 119
  • 別自作多情了 盡管你專(zhuān)程而來(lái) 那么深情干嘛 我敞開(kāi)的門(mén) 只為天空 費(fèi)盡心思杜撰著 我的寂寞 其實(shí)我 習(xí)慣了孤獨(dú) 你...
    一杯老酒閱讀 1,307評(píng)論 29 17
  • 滿(mǎn)地的落葉見(jiàn)證了秋的結(jié)束。 他和她來(lái)到這里。 相戀三年,彼此深深地刻在對(duì)方骨子里。他是刑警,要去執(zhí)行任務(wù),在這片樹(shù)...
    我愛(ài)健康閱讀 245評(píng)論 2 2
  • 七夕至,鵲橋邊,來(lái)相會(huì),人未至,心已醉。 月亮船,花海邊,一玫瑰,望秋水,相思淚。 銀河岸,各一邊,繁星點(diǎn),借明月...
    快樂(lè)的Alina閱讀 528評(píng)論 21 23
  • 看到這個(gè)題目,以你一定得奇怪,世上哪有這種糖。我怎么沒(méi)見(jiàn)過(guò),看來(lái)不動(dòng)腦筋是不行的我不發(fā),直接告訴你吧。 那天晚飯后...
    小美su閱讀 580評(píng)論 0 0

友情鏈接更多精彩內(nèi)容