- import 'dart:async';
- import 'package:flutter/material.dart';
- import 'package:rxdart/subjects.dart';
-
- double ourMap(v, start1, stop1, start2, stop2) {
- return (v - start1) / (stop1 - start1) * (stop2 - start2) + start2;
- }
-
- void main() => runApp(MyApp());
-
- class MyApp extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- home: HomePage(),
- );
- }
- }
-
- class HomePage extends StatefulWidget {
- @override
- _HomePageState createState() => _HomePageState();
- }
-
- class _HomePageState extends State<HomePage>
- with SingleTickerProviderStateMixin {
- final int initPage = 0;
- PageController _pageController;
- List<String> tabs = ['aaa', 'bbb', 'ccc', 'ddd', 'eee'];
-
- 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 Scaffold(
- body: Column(
- children: <Widget>[
- SizedBox(height: MediaQuery.of(context).padding.top + 20),
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 12.0),
- child: Container(
- height: 40,
- decoration: BoxDecoration(
- color: Colors.black38,
- borderRadius: BorderRadius.circular(35),
- ),
- child: Stack(
- children: <Widget>[
- // use animation controller
- // Align(
- // alignment: _dragAlignment,
- // child: LayoutBuilder(
- // builder:
- // (BuildContext context, BoxConstraints constraints) {
- // double width = constraints.maxWidth;
- // return Padding(
- // padding: const EdgeInsets.all(2.0),
- // child: Container(
- // height: double.infinity,
- // width: width / tabs.length,
- // decoration: BoxDecoration(
- // color: Colors.white,
- // borderRadius: BorderRadius.circular(35),
- // ),
- // ),
- // );
- // },
- // ),
- // ),
-
- // use animated 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: Container(
- height: double.infinity,
- width: width / tabs.length,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(35),
- ),
- ),
- );
- },
- ),
- );
- }
- return SizedBox();
- },
- ),
- Align(
- alignment: Alignment.center,
- child: Row(
- children: tabs.map((t) {
- int index = tabs.indexOf(t);
- return Expanded(
- child: MaterialButton(
- splashColor: Colors.transparent,
- focusColor: Colors.transparent,
- color: Colors.transparent,
- highlightColor: Colors.transparent,
- hoverColor: Colors.transparent,
- focusElevation: 0.0,
- hoverElevation: 0.0,
- elevation: 0.0,
- highlightElevation: 0.0,
- child: StreamBuilder(
- stream: currentPage$,
- builder:
- (context, AsyncSnapshot<int> snapshot) {
- return AnimatedDefaultTextStyle(
- duration: kThemeAnimationDuration,
- style: TextStyle(
- inherit: true,
- color: snapshot.data == index
- ? Colors.black
- : Colors.white,
- ),
- child: Text(t),
- );
- }),
- onPressed: () {
- currentPageSink.add(index);
- _pageController.jumpToPage(index);
- },
- ),
- );
- }).toList(),
- ),
- ),
- ],
- ),
- ),
- ),
- Expanded(
- child: PageView(
- controller: _pageController,
- onPageChanged: (page) => currentPageSink.add(page),
- children: <Widget>[
- for (var t in tabs)
- Center(
- child: Text(t),
- )
- ],
- ),
- ),
- ],
- ),
- );
- }
- }