当前位置:   article > 正文

flutter 自定义TabBar

flutter tabbar borderradius

demo.gif

  1. import 'dart:async';
  2. import 'package:flutter/material.dart';
  3. import 'package:rxdart/subjects.dart';
  4. double ourMap(v, start1, stop1, start2, stop2) {
  5. return (v - start1) / (stop1 - start1) * (stop2 - start2) + start2;
  6. }
  7. void main() => runApp(MyApp());
  8. class MyApp extends StatelessWidget {
  9. @override
  10. Widget build(BuildContext context) {
  11. return MaterialApp(
  12. home: HomePage(),
  13. );
  14. }
  15. }
  16. class HomePage extends StatefulWidget {
  17. @override
  18. _HomePageState createState() => _HomePageState();
  19. }
  20. class _HomePageState extends State<HomePage>
  21. with SingleTickerProviderStateMixin {
  22. final int initPage = 0;
  23. PageController _pageController;
  24. List<String> tabs = ['aaa', 'bbb', 'ccc', 'ddd', 'eee'];
  25. Stream<int> get currentPage$ => _currentPageSubject.stream;
  26. Sink<int> get currentPageSink => _currentPageSubject.sink;
  27. BehaviorSubject<int> _currentPageSubject;
  28. Alignment _dragAlignment;
  29. AnimationController _controller;
  30. Animation<Alignment> _animation;
  31. @override
  32. void initState() {
  33. super.initState();
  34. _currentPageSubject = BehaviorSubject<int>.seeded(initPage);
  35. _pageController = PageController(initialPage: initPage);
  36. _dragAlignment = Alignment(ourMap(initPage, 0, tabs.length - 1, -1, 1), 0);
  37. _controller = AnimationController(
  38. vsync: this,
  39. duration: kThemeAnimationDuration,
  40. )..addListener(() {
  41. setState(() {
  42. _dragAlignment = _animation.value;
  43. });
  44. });
  45. currentPage$.listen((int page) {
  46. _runAnimation(
  47. _dragAlignment,
  48. Alignment(ourMap(page, 0, tabs.length - 1, -1, 1), 0),
  49. );
  50. });
  51. }
  52. @override
  53. void dispose() {
  54. _currentPageSubject.close();
  55. _pageController.dispose();
  56. _controller.dispose();
  57. super.dispose();
  58. }
  59. void _runAnimation(Alignment oldA, Alignment newA) {
  60. _animation = _controller.drive(
  61. AlignmentTween(
  62. begin: oldA,
  63. end: newA,
  64. ),
  65. );
  66. _controller.reset();
  67. _controller.forward();
  68. }
  69. @override
  70. Widget build(BuildContext context) {
  71. return Scaffold(
  72. body: Column(
  73. children: <Widget>[
  74. SizedBox(height: MediaQuery.of(context).padding.top + 20),
  75. Padding(
  76. padding: const EdgeInsets.symmetric(horizontal: 12.0),
  77. child: Container(
  78. height: 40,
  79. decoration: BoxDecoration(
  80. color: Colors.black38,
  81. borderRadius: BorderRadius.circular(35),
  82. ),
  83. child: Stack(
  84. children: <Widget>[
  85. // use animation controller
  86. // Align(
  87. // alignment: _dragAlignment,
  88. // child: LayoutBuilder(
  89. // builder:
  90. // (BuildContext context, BoxConstraints constraints) {
  91. // double width = constraints.maxWidth;
  92. // return Padding(
  93. // padding: const EdgeInsets.all(2.0),
  94. // child: Container(
  95. // height: double.infinity,
  96. // width: width / tabs.length,
  97. // decoration: BoxDecoration(
  98. // color: Colors.white,
  99. // borderRadius: BorderRadius.circular(35),
  100. // ),
  101. // ),
  102. // );
  103. // },
  104. // ),
  105. // ),
  106. // use animated widget
  107. StreamBuilder(
  108. stream: currentPage$,
  109. builder: (context, AsyncSnapshot<int> snapshot) {
  110. if (snapshot.connectionState == ConnectionState.active) {
  111. return AnimatedAlign(
  112. duration: kThemeAnimationDuration,
  113. alignment: Alignment(
  114. ourMap(snapshot.data, 0, tabs.length - 1, -1, 1),
  115. 0),
  116. child: LayoutBuilder(
  117. builder: (BuildContext context,
  118. BoxConstraints constraints) {
  119. double width = constraints.maxWidth;
  120. return Padding(
  121. padding: const EdgeInsets.all(2.0),
  122. child: Container(
  123. height: double.infinity,
  124. width: width / tabs.length,
  125. decoration: BoxDecoration(
  126. color: Colors.white,
  127. borderRadius: BorderRadius.circular(35),
  128. ),
  129. ),
  130. );
  131. },
  132. ),
  133. );
  134. }
  135. return SizedBox();
  136. },
  137. ),
  138. Align(
  139. alignment: Alignment.center,
  140. child: Row(
  141. children: tabs.map((t) {
  142. int index = tabs.indexOf(t);
  143. return Expanded(
  144. child: MaterialButton(
  145. splashColor: Colors.transparent,
  146. focusColor: Colors.transparent,
  147. color: Colors.transparent,
  148. highlightColor: Colors.transparent,
  149. hoverColor: Colors.transparent,
  150. focusElevation: 0.0,
  151. hoverElevation: 0.0,
  152. elevation: 0.0,
  153. highlightElevation: 0.0,
  154. child: StreamBuilder(
  155. stream: currentPage$,
  156. builder:
  157. (context, AsyncSnapshot<int> snapshot) {
  158. return AnimatedDefaultTextStyle(
  159. duration: kThemeAnimationDuration,
  160. style: TextStyle(
  161. inherit: true,
  162. color: snapshot.data == index
  163. ? Colors.black
  164. : Colors.white,
  165. ),
  166. child: Text(t),
  167. );
  168. }),
  169. onPressed: () {
  170. currentPageSink.add(index);
  171. _pageController.jumpToPage(index);
  172. },
  173. ),
  174. );
  175. }).toList(),
  176. ),
  177. ),
  178. ],
  179. ),
  180. ),
  181. ),
  182. Expanded(
  183. child: PageView(
  184. controller: _pageController,
  185. onPageChanged: (page) => currentPageSink.add(page),
  186. children: <Widget>[
  187. for (var t in tabs)
  188. Center(
  189. child: Text(t),
  190. )
  191. ],
  192. ),
  193. ),
  194. ],
  195. ),
  196. );
  197. }
  198. }

转载于:https://www.cnblogs.com/ajanuw/p/11456688.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/431760
推荐阅读
相关标签
  

闽ICP备14008679号