Flutter 自定义吸顶动画
2020-05-26 本文已影响0人
Charles2018
效果预览:
PREVIEW我这里没有录制GIF的工具所以勉强看吧 此Demo仅仅是个思路 实际使用时根据UI设计进行更改
源代码
c_tab_bar.dart
import 'package:flutter/material.dart';
class CTabBar extends StatefulWidget {
final List<Widget> tabs;
final Color labelColor;
final bool isScrollable;
final Decoration indicator;
final TextStyle labelStyle;
final Function onScrollEvent;
final Color unselectedLabelColor;
final TextStyle unselectedLabelStyle;
CTabBar(
{Key key,
this.tabs,
this.indicator,
this.labelStyle,
this.labelColor,
this.isScrollable,
this.onScrollEvent,
this.unselectedLabelColor,
this.unselectedLabelStyle})
: super(key: key);
@override
State<StatefulWidget> createState() => CTabBarState();
}
class CTabBarState extends State<CTabBar> with SingleTickerProviderStateMixin {
TabController tabController;
@override
int get index => tabController.index;
@override
get indexIsChanging => tabController.indexIsChanging;
@override
double get offset => tabController.offset;
void animateTo(int index) {
tabController.animateTo(index);
}
@override
void initState() {
super.initState();
tabController = TabController(length: widget.tabs.length, vsync: this);
tabController.addListener(widget.onScrollEvent);
}
@override
Widget build(BuildContext context) {
return TabBar(
tabs: widget.tabs,
controller: tabController,
indicator: widget.indicator,
labelColor: widget.labelColor,
labelStyle: widget.labelStyle,
isScrollable: widget.isScrollable,
unselectedLabelColor: widget.unselectedLabelColor,
unselectedLabelStyle: widget.unselectedLabelStyle,
);
}
}
- main.dart
import 'package:flutter/material.dart';
import 'CTabBar.dart';
void main() => runApp(
MaterialApp(
home:MyHomePage()
),
);
class MyHomePage extends StatefulWidget{
@override
State<StatefulWidget> createState() => HomeState();
}
class HomeState extends State<MyHomePage>{
static bool isCollapsed = false;
ScrollController scrollController = new ScrollController();
var isPageCanChanged = true;
GlobalKey<CTabBarState> globalKeyCTabBar = new GlobalKey();
PageController mPageController = PageController(initialPage: 0);
static final List<Tab> tabList = [
Tab(text: '推荐'),
Tab(text: '热点'),
Tab(text: '社会'),
Tab(text: '娱乐')
];
@override
void initState() {
super.initState();
scrollController.addListener(() {
var offset = scrollController.offset;
print('offset: $offset');
if (offset <= 1) {
setState(() {
isCollapsed = false;
});
} else if (offset >= 1) {
setState(() {
isCollapsed = true;
});
}
});
}
void onPageChange(int index, {PageController pageController}) async {
if (pageController != null) {
isPageCanChanged = false;
await mPageController.animateToPage(index,
duration: Duration(milliseconds: 500), curve: Curves.ease);
isPageCanChanged = true;
} else {
globalKeyCTabBar.currentState.animateTo(index);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.topCenter,
children: <Widget>[
// 背景
AnimatedContainer(
height: isCollapsed ? 120 : 320,
color: Colors.yellowAccent,
duration: Duration(milliseconds: 280),
curve: Curves.fastOutSlowIn,
),
// 搜索栏
AnimatedContainer(
height: isCollapsed ? 0 : 180,
width: MediaQuery.of(context).size.width,
color: Colors.lightBlue,
duration: Duration(milliseconds: 280),
curve: Curves.fastOutSlowIn,
padding: EdgeInsets.only(top:30,bottom:80),
child: Container(
alignment: Alignment.center,
height: 50,
color: Colors.purple,
child: Text(
"搜索栏",
textAlign: TextAlign.center,
textScaleFactor: 2,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
// Tab栏
AnimatedContainer(
margin: EdgeInsets.only(top: isCollapsed ? 35 : 110),
duration: Duration(milliseconds: 500),
curve: Curves.fastOutSlowIn,
child:Column(
children: <Widget>[
Container(
height:30,
margin:EdgeInsets.only(bottom:isCollapsed ? 8 : 0),
child: CTabBar(
key: globalKeyCTabBar,
onScrollEvent: () {
if (globalKeyCTabBar.currentState.indexIsChanging) {
onPageChange(globalKeyCTabBar.currentState.index,
pageController: mPageController);
}
},
tabs: tabList,
isScrollable: false,
indicator: BoxDecoration(
gradient:LinearGradient(
colors: [Colors.purpleAccent,Colors.blue],
),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20),
),
labelColor: Colors.white,
labelStyle: TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold,
),
unselectedLabelColor: Colors.black54,
unselectedLabelStyle: TextStyle(
fontSize: 18,
color: Colors.black54,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: PageView.builder(
itemCount: tabList.length,
onPageChanged: (index) {
if (isPageCanChanged) {
onPageChange(index);
}
},
controller: mPageController,
itemBuilder: (BuildContext context, int index) {
return Container(
child: ListView(
controller: scrollController,
children:[1,1,1,1,1,1,1,1,1,1,1,1,1].map<Widget>(
(v) => Container(
height: 150,
margin: EdgeInsets.only(
bottom: 10,
left: 15,
right: 15,
),
decoration: BoxDecoration(
gradient:LinearGradient(
colors:[
Colors.red,
Colors.purpleAccent,
],
),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(15),
),
),
).toList(),
),
);
},
),
),
],
),
),
],
),
);
}
}