Flutter實現(xiàn)動畫卡片式Tab導(dǎo)航

前言

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

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

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

外觀

實現(xiàn)

這里是我的代碼: GitHub/Realank

想使用這個控件非常簡單,首先定義頁面數(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('第一頁'))),
  new CardSection(
      title: 'Second Page',
      leftColor: _mariner,
      rightColor: _mySin,
      contentWidget: Center(child: new Text('第二頁'))),
  new CardSection(
      title: 'Third Page',
      leftColor: _mySin,
      rightColor: _tomato,
      contentWidget: Center(child: new Text('第三頁'))),
  new CardSection(
      title: 'Forth Page',
      leftColor: _tomato,
      rightColor: Colors.blue,
      contentWidget: Center(child: new Text('第四頁'))),
  new CardSection(
      title: 'Fifth Page',
      leftColor: Colors.blue,
      rightColor: _mediumPurple,
      contentWidget: Center(child: new Text('第五頁'))),
];

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

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,
          ),
        ),
      ),
    );
  }
}

大功告成

原理

知其然還要知其所以然,下面來說說這個控件的實現(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;
}

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

然后在widgets.dart中定義了幾個widget:

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

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

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

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

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

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