flutter使用PageController和AnimationController和自定义widget实现自定义tabbar

427 阅读1分钟
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.
    );
  }
}

效果如下

参考资料

www.cnblogs.com/ajanuw/p/11…