flutter 自定义TabBar

Posted ajanuw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flutter 自定义TabBar相关的知识,希望对你有一定的参考价值。

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),
                  )
              ],
            ),
          ),
        ],
      ),
    );
  

以上是关于flutter 自定义TabBar的主要内容,如果未能解决你的问题,请参考以下文章

Flutter AppBar基本用法、TabBar基本用法、自定义TabBar

iOS 自定义TabBarController zhuanzai

设置tabBar使用第三方插件和自定义组件使用简单实例

六Flutter自定义Tabbar

如何像 Flutter 中的专业人士一样创建自定义大小的 TabBar?

将自定义小部件添加到 Flutter TabBar 的活动选项卡