Flutter實現動畫卡片式Tab導航 | 掘金技術徵文

前言

本人接觸Flutter不到一個月,深深感覺到了這個平臺的威力,因而不斷學習,Flutter官方Example中的flutter_gallery,很好的展現了Flutter各個widget的功能git

其中的animation內容,展現的是一個很是漂亮的 帶有動畫和拖拽功能的 可展開的卡片式Tab導航,很是漂亮,可是其實現沒有抽象出一個可供第三方使用的Widget出來,並且其頁面內容的定製性不夠友好,滑動的時候也有bug,我在他的基礎上進行了優化github

官方展現了一個很是好的開源示例,我改造了一下,也不敢獨自享用,如今分享給你們,歡迎你們多多交流bash

外觀

實現

這裏是個人代碼: GitHub/Realank數據結構

想使用這個控件很是簡單,首先定義頁面數據:app

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('第五頁'))),
];
複製代碼

而後建立這個控件:less

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,
          ),
        ),
      ),
    );
  }
}
複製代碼

大功告成ide

原理

知其然還要知其因此然,下面來講說這個控件的實現原理佈局

首先,在sections.dart裏定義了數據結構:post

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

複製代碼

它定義了其中一個卡片的標題,左邊顏色和右邊顏色(爲了顯示過渡顏色效果),以及子控件(這個是我改進的,這樣能夠別人使用的時候隨意添加控件)學習

而後在widgets.dart中定義了幾個widget:

  • SectionCard : 標題卡片
  • SectionTitle : 標題
  • SectionIndicator : 標題下的裝飾線

最後在cardNavigation.dart中就是佈局這些內容啦,這裏面代碼很複雜,其思路卻是不難:

  1. 定義全屏展現tab的高度maxHeight,以及打開tab後,tab顯示在頂部的高度minHeight
  2. 在用戶拖動tab卡片的時候,根據卡片的位置於minHeight和maxHeight的比例,計算出動畫進度(0.0-1.0)
  3. 在_AllSectionsLayout中,定義了全屏顯示tab時,卡片的columnCardRect,以及打開tab後,tab顯示在頂部時候的rowCardRectt
  4. 計算出這兩個rect在動畫進度0-1過程當中的中間態的rect尺寸,賦值給每個卡片,這樣卡片就有中間狀態的外觀了。
  5. 當用戶點擊了tab區域,就會觸發_maybeScroll方法,這個方法判斷當前的tab是全屏的仍是打開後的
  6. 當tab是全屏的,就展開對應的tab頁
  7. 當tab已是打開的,就判斷點擊的位置,在tab欄的左側,就往左翻頁,反之亦然。

從 0 到 1:個人 Flutter 技術實踐 | 掘金技術徵文,徵文活動正在進行中

相關文章
相關標籤/搜索