import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
double ourMap(v, start1, stop1, start2, stop2) {
return (v - start1) / (stop1 - start1) * (stop2 - start2) + start2;
}
class TabEntry{
String title;
String mount;
TabEntry(this.title, this.mount);
}
class MyTabBar extends StatefulWidget {
List<TabEntry> tabs ;
List<Widget> pageViews ;
MyTabBar(this.tabs, this.pageViews);
@override
_MyTabBarState createState() => _MyTabBarState(this.tabs, this.pageViews);
}
class _MyTabBarState extends State<MyTabBar>
with SingleTickerProviderStateMixin {
final int initPage = 0;
PageController _pageController;
List<TabEntry> tabs ;
List<Widget> pageViews ;
Stream<int> get currentPage$ => _currentPageSubject.stream;
Sink<int> get currentPageSink => _currentPageSubject.sink;
BehaviorSubject<int> _currentPageSubject;
Alignment _dragAlignment;
AnimationController _controller;
Animation<Alignment> _animation;
@override
void initState() {
super.initState();
_currentPageSubject = BehaviorSubject<int>.seeded(initPage);
_pageController = PageController(initialPage: initPage);
_dragAlignment = Alignment(ourMap(initPage, 0, tabs.length - 1, -1, 1), 0);
_controller = AnimationController(
vsync: this,
duration: kThemeAnimationDuration,
)..addListener(() {
setState(() {
_dragAlignment = _animation.value;
});
});
currentPage$.listen((int page) {
_runAnimation(
_dragAlignment,
Alignment(ourMap(page, 0, tabs.length - 1, -1, 1), 0),
);
});
}
@override
void dispose() {
_currentPageSubject.close();
_pageController.dispose();
_controller.dispose();
super.dispose();
}
void _runAnimation(Alignment oldA, Alignment newA) {
_animation = _controller.drive(
AlignmentTween(
begin: oldA,
end: newA,
),
);
_controller.reset();
_controller.forward();
}
@override
Widget build(BuildContext context) {
return Container(child: Column(
children: <Widget>[
SizedBox(height: 20),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Container(
child: Stack(
children: <Widget>[
StreamBuilder(
stream: currentPage$,
builder: (context, AsyncSnapshot<int> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
return AnimatedAlign(
duration: kThemeAnimationDuration,
alignment: Alignment(
ourMap(snapshot.data, 0, tabs.length - 1, -1, 1),
0),
child: LayoutBuilder(
builder: (BuildContext context,
BoxConstraints constraints) {
double width = constraints.maxWidth;
return Padding(
padding: const EdgeInsets.all(2.0),
child: Column(
children: [
Padding(padding: EdgeInsets.all(20.0)),
//次数为指示器
Container(
height:2,
width: width / tabs.length,
color: Colors.red,
),
],
),
);
},
),
);
}
return SizedBox();
},
),
Align(
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: tabs.map((t) {
int index = tabs.indexOf(t);
//此处为tab的内容
return Column(children: [
Text(tabs[index].title),
Text(tabs[index].mount)
],);
}).toList(),
),
}_MyTabBarState(this.tabs, this.pageViews);
首先要添加rxflutter依赖在pubspec.yaml文件中添加
rxdart:
使用时
class _MyHomePageState extends State<MyHomePage> {
List<TabEntry> tabs = [TabEntry("全部","60"),TabEntry("待领养","20"),TabEntry("已领养","20"),];
List<Widget> pageViews = [Text("全部"),Text("待领养"),Text("已领养"),];
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: MyTabBar(tabs,pageViews),
// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
效果如下
参考资料