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的更多相关文章

  1. flutter 自定义tabbar 给tabbar添加背景功能

    flutter 自带的tabbar BottomNavigationBar有长按水波纹效果,不可以添加背景图片功能,如果有这方面的需求,就需要自定义tabbar了 自定义图片 我们使用BottomAp ...

  2. Flutter实战视频-移动电商-46.详细页_自定义TabBar Widget

    46.详细页_自定义TabBar Widget 主要实现详情和评论的tab provide定义变量 自己做一个tab然后用provide去控制 定义两个变量来判断是左侧选中了还是右侧选中了.并定义一个 ...

  3. 19 Flutter 自定义AppBar 定义顶部Tab切换 底部Tab结合顶部Tab实现类似头条页面布局(27分36秒)

    Flutter AppBar自定义顶部导航按钮图标.颜色以及TabBar定义顶部Tab切换. leading:在标题前面显示的一个控件,在首页通常显示应用的logo:在其他界面通常显示为付汇按钮. t ...

  4. 自定义tabBar

    ★★★★自定义tabBar★★★★★★★ Demo下载地址:https://github.com/marlonxlj/tabBarCustom.git 前言: 有的时候需求要对tabBar进行自定义的 ...

  5. IOS第二天-新浪微博 - 添加搜索框,弹出下拉菜单 ,代理的使用 ,HWTabBar.h(自定义TabBar)

    ********HWDiscoverViewController.m(发现) - (void)viewDidLoad { [super viewDidLoad]; // 创建搜索框对象 HWSearc ...

  6. iOS 隐藏自定义tabbar

    iOS  隐藏自定义tabbar -(void)viewWillAppear:(BOOL)animated { NSArray *array=self.tabBarController.view.su ...

  7. iOS开发之功能模块--关于自定义TabBar条

    只上项目中用到的代码: 1.实现重写TabBar的TabBarItem,然后在中间额外加一个按钮. #import <UIKit/UIKit.h> @interface BikeTabBa ...

  8. iOS开发项目之四 [ 调整自定义tabbar的位置与加号按钮的位置]

    自定义tabbar与按钮的添加 01 - 把系统的tabbar用我们自己的覆盖 LHQTabBar *lhqTabBar = [[LHQTabBar alloc]init]; [self setVal ...

  9. 关于自定义tabBar时修改系统自带tabBarItem属性造成的按钮顺序错乱的问题相关探究

      关于自定义tabBar时修改系统自带tabBarItem属性造成的按钮顺序错乱的问题相关探究 测试代码:http://git.oschina.net/Xiyue/TabBarItem_TEST 简 ...

随机推荐

  1. SVN、GIT比较

    Git是分布式的,完全可以不备份代码,下载下来后,在本地不必联网就可以看到所有的log,跟其他同事不会有太多的冲突,自己写的代码放在自己电脑上,一段时间后再提交.合并,也可以不用联网在本地提交 SVN ...

  2. 大数据体系概览Spark、Spark核心原理、架构原理、Spark特点

    大数据体系概览Spark.Spark核心原理.架构原理.Spark特点 大数据体系概览(Spark的地位) 什么是Spark? Spark整体架构 Spark的特点 Spark核心原理 Spark架构 ...

  3. (29)Vim 5

    Vim显示行号方法详解1.编辑时显示行号 在命令模式下输入":set nu"即可显示每一行的行号 如果想要取消行 号,则再次输入":set nonu"即可.2. ...

  4. HTML学习速记

    HTML结构导图 先看HTML结构示意图 本文主要讲解HTML当中的一些html标签,css样式,javascript方法 html html的标签有各式各样的数不胜数,但是常用的并不多,总结下我目前 ...

  5. Pytest(6)重复运行用例pytest-repeat

    前言 平常在做功能测试的时候,经常会遇到某个模块不稳定,偶然会出现一些bug,对于这种问题我们会针对此用例反复执行多次,最终复现出问题来. 自动化运行用例时候,也会出现偶然的bug,可以针对单个用例, ...

  6. AtCoder Beginner Contest 176

    比赛链接:https://atcoder.jp/contests/abc176 A - Takoyaki #include <bits/stdc++.h> using namespace ...

  7. Codeforces Round #652 (Div. 2) B. AccurateLee(字符串)

    题目链接:https://codeforces.com/contest/1369/problem/B 题意 给出一个长 $n$ 的 二进制串,每次可以选择字符串中的一个 $10$,然后删除其中的一个字 ...

  8. Codeforces Round #628 (Div. 2) B. CopyCopyCopyCopyCopy(Set)

    题意: 给你一个数组,可以像题目那样无限拼接,问递增子序列的最大长度(可不连续). 思路: 序列的最大长度即为数组中不同元素的个数. Tips: 一开始不知道back-to-back什么意思,看到题目 ...

  9. Codeforces Round #481 (Div. 3) G. Petya's Exams (贪心,模拟)

    题意:你有\(n\)天的时间,这段时间中你有\(m\)长考试,\(s\)表示宣布考试的日期,\(d\)表示考试的时间,\(c\)表示需要准备时间,如果你不能准备好所有考试,输出\(-1\),否则输出你 ...

  10. Java基础(第二期)

    数据类型扩展以及面试题讲解 整数拓展:进制 int i=10; int i2=010; //八进制0 int i3=0x10; //十六进制0x 0~9 A~F 16 相关进制转换自行学习,用的不多 ...