tab_card.dart 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import 'package:flutter/material.dart';
  2. class TabCard extends StatefulWidget {
  3. final List<Widget> titles;
  4. final List<Widget> bodies;
  5. final MainAxisAlignment titleAlign;
  6. final Alignment bodyAlign;
  7. final FlexFit titleFit;
  8. final EdgeInsetsGeometry? titlePadding;
  9. final BoxDecoration titleDecoration;
  10. final BoxDecoration titleActiveDecoration;
  11. final Axis direction;
  12. const TabCard({
  13. Key? key,
  14. required this.titles,
  15. required this.bodies,
  16. this.direction = Axis.vertical,
  17. this.titleAlign = MainAxisAlignment.start,
  18. this.titlePadding,
  19. this.titleDecoration =
  20. const BoxDecoration(color: Color.fromRGBO(0, 0, 0, .1)),
  21. this.titleActiveDecoration = const BoxDecoration(color: Colors.white),
  22. this.titleFit = FlexFit.loose,
  23. this.bodyAlign = Alignment.topLeft,
  24. }) : super(key: key);
  25. @override
  26. State<TabCard> createState() => TabCardState();
  27. }
  28. class TabCardState extends State<TabCard> {
  29. int index = 0;
  30. late List<Widget> titles;
  31. late ValueNotifier<int> onTabChange;
  32. @override
  33. void initState() {
  34. super.initState();
  35. onTabChange = ValueNotifier<int>(index);
  36. titles = widget.titles.map<Widget>((e) {
  37. int curIndex = widget.titles.indexOf(e);
  38. return Flexible(
  39. flex: widget.titleFit == FlexFit.tight ? 0 : 1,
  40. fit: widget.titleFit,
  41. child: TabCardTitleItem(
  42. myIndex: curIndex,
  43. child: e,
  44. ),
  45. );
  46. }).toList();
  47. }
  48. void updateIndex(int i) {
  49. setState(() {
  50. index = i;
  51. });
  52. onTabChange.value = i;
  53. }
  54. @override
  55. Widget build(BuildContext context) {
  56. return Flex(
  57. direction: widget.direction,
  58. children: [
  59. Container(
  60. decoration: widget.titleDecoration,
  61. child: Flex(
  62. direction: widget.direction == Axis.horizontal
  63. ? Axis.vertical
  64. : Axis.horizontal,
  65. mainAxisSize: MainAxisSize.max,
  66. mainAxisAlignment: widget.titleAlign,
  67. children: titles,
  68. ),
  69. ),
  70. Expanded(
  71. child: IndexedStack(
  72. index: index,
  73. alignment: widget.bodyAlign,
  74. sizing: StackFit.expand,
  75. children: widget.bodies,
  76. ),
  77. ),
  78. ],
  79. );
  80. }
  81. }
  82. class TabCardTitleItem extends StatefulWidget {
  83. final int myIndex;
  84. final Widget child;
  85. const TabCardTitleItem({Key? key, required this.myIndex, required this.child})
  86. : super(key: key);
  87. @override
  88. State<TabCardTitleItem> createState() => TabCardTitleItemState();
  89. }
  90. class TabCardTitleItemState extends State<TabCardTitleItem> {
  91. bool isActive = false;
  92. TabCardState? tabCard;
  93. @override
  94. void initState() {
  95. super.initState();
  96. tabCard = context.findRootAncestorStateOfType<TabCardState>();
  97. if (tabCard != null) {
  98. if (widget.myIndex == tabCard!.index) {
  99. isActive = true;
  100. }
  101. tabCard?.onTabChange.addListener(indexListener);
  102. }
  103. }
  104. void indexListener() {
  105. setState(() {
  106. isActive = tabCard!.index == widget.myIndex;
  107. });
  108. }
  109. @override
  110. Widget build(BuildContext context) {
  111. return GestureDetector(
  112. onTap: () {
  113. tabCard?.updateIndex(widget.myIndex);
  114. },
  115. child: AnimatedContainer(
  116. duration: const Duration(milliseconds: 300),
  117. curve: Curves.easeOutQuint,
  118. padding: tabCard!.widget.titlePadding,
  119. decoration: isActive
  120. ? tabCard!.widget.titleActiveDecoration
  121. : tabCard!.widget.titleDecoration,
  122. child: Center(child: widget.child),
  123. ),
  124. );
  125. }
  126. @override
  127. void dispose() {
  128. tabCard?.onTabChange.removeListener(indexListener);
  129. super.dispose();
  130. }
  131. }