前言
本人接觸Flutter不到一個月,深深感受到了這個平臺的威力,於是不斷學習,Flutter官方Example中的flutter_gallery,很好的展示了Flutter各個widget的功能
其中的animation內容,展示的是一個非常漂亮的
帶有動畫和拖拽功能的
可展開的
卡片式Tab導航,非常漂亮,但是其實現沒有抽象出一個可供第三方使用的Widget出來,而且其頁面內容的定製性不夠友好,滑動的時候也有bug,我在他的基礎上進行了優化
官方展示了一個非常好的開源示例,我改造了一下,也不敢獨自享用,現在分享給大家,歡迎大家多多交流
外觀
實現
這裡是我的程式碼: GitHub/Realank
想使用這個控制元件非常簡單,首先定義頁面資料:
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('第五頁'))),
];
複製程式碼
然後建立這個控制元件:
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,
),
),
),
);
}
}
複製程式碼
大功告成
原理
知其然還要知其所以然,下面來說說這個控制元件的實現原理
首先,在sections.dart裡定義了資料結構:
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中就是佈局這些內容啦,這裡面程式碼很複雜,其思路倒是不難:
- 定義全屏展示tab的高度maxHeight,以及開啟tab後,tab顯示在頂部的高度minHeight
- 在使用者拖動tab卡片的時候,根據卡片的位置於minHeight和maxHeight的比例,計算出動畫進度(0.0-1.0)
- 在_AllSectionsLayout中,定義了全屏顯示tab時,卡片的columnCardRect,以及開啟tab後,tab顯示在頂部時候的rowCardRectt
- 計算出這兩個rect在動畫進度0-1過程中的中間態的rect尺寸,賦值給每一個卡片,這樣卡片就有中間狀態的外觀了。
- 當使用者點選了tab區域,就會觸發_maybeScroll方法,這個方法判斷當前的tab是全屏的還是開啟後的
- 當tab是全屏的,就展開對應的tab頁
- 當tab已經是開啟的,就判斷點選的位置,在tab欄的左側,就往左翻頁,反之亦然。