In the process of practical learning, the TabBar TabBar needs to be left by default, while TabBar is in the center by default. Take this opportunity to learn TabBar source code, slightly adjust the alignment;
ACETabBar
ACETabBarAlignType Alignment
The side dish adds a alignType to set the alignment of the ACETabBar; Set isScrollable = true; When isScrollable = false, TabBar and isScrollable have the same effect as TabBar.
enum ACETabBarAlignType { left, center, right }
Copy the code
Source code analysis
TabBar in _TabBarState TabBar drawing process, multiple sub-tab through SingleChildScrollView storage, the simplest way, Add a Container outside SingleChildScrollView that allows you to set the alignment.
if (widget.isScrollable) { _scrollController ?? = _TabBarScrollController(this); tabBar = Container( alignment: _alignType(widget.alignType ?? ACETabBarAlignType.center), child: _scrollView(tabBar)); } _alignType(alignType) { Alignment _type; switch (alignType) { case ACETabBarAlignType.left: _type = Alignment.centerLeft; break; case ACETabBarAlignType.center: _type = Alignment.center; break; case ACETabBarAlignType.right: _type = Alignment.centerRight; break; } return _type; } _scrollView(tabBar) { return SingleChildScrollView( dragStartBehavior: widget.dragStartBehavior, scrollDirection: Axis.horizontal, controller: _scrollController, physics: widget.physics, child: tabBar); }Copy the code
Case try
The side dish tries the alignment of the ACETabBar in two states: whether or not the isScrollable is slidable.
_tabBar01() => ACETabBar(isScrollable: true, controller: _tabController, tabs: <Widget>[Tab(text: 'today ', icon: Account_circle), Tab(text: 'Icons. Account_circle '), Tab(text:' sort ')); _tabBar02() => ACETabBar( isScrollable: true, alignType: ACETabBarAlignType.left, controller: _tabController, tabs: < widgets > [Tab (text: 'today's hot style), the Tab (text:' today's hot style goods from home fresh abroad), the Tab (text: 'classification')]); _tabBar03() => ACETabBar( isScrollable: true, alignType: ACETabBarAlignType.right, controller: _tabController, tabs: < widgets > [Tab (text: 'today's hot style), the Tab (text:' today's hot style goods from home fresh abroad), the Tab (text: 'classification')]); _tabBar04() => ACETabBar( isScrollable: false, alignType: ACETabBarAlignType.right, controller: _tabController, tabs: < widgets > [Tab (text: 'today's hot style), the Tab (text:' today's hot style goods from home fresh abroad), the Tab (text: 'classification')]);Copy the code
StartIcon & endIcon Fixed bit icon
Similar to many news or mall apps, TabBar usually has small widgets such as fixed ICONS or text on the left and right sides. For the side dish, startIcon and endIcon ICONS were added after the alignment was set.
Source code analysis
When setting the alignment, the small dish learned that _TabBarState was used to draw the TabBar to show whether it could slide or not. The small dish added two startIcon and endIcon properties, and judged whether the display was added to the navigation bar when the TabBar was finally returned. Whether to add a click event can be handled by adding the Widget;
Widget tabBar = CustomPaint( painter: _indicatorPainter, child: _TabStyle( animation: kAlwaysDismissedAnimation, selected: false, labelColor: widget.labelColor, unselectedLabelColor: widget.unselectedLabelColor, labelStyle: widget.labelStyle, unselectedLabelStyle: widget.unselectedLabelStyle, child: _TabLabelBar(onPerformLayout: _saveTabOffsets, children: wrappedTabs))); if (widget.isScrollable) { _scrollController ?? = _TabBarScrollController(this); tabBar = Container( alignment: _alignType(widget.alignType ?? ACETabBarAlignType.center), child: _scrollView(tabBar)); } tabBar = Row(children: [ widget.startIcon ?? Container(), Flexible(child: tabBar), widget.endIcon ?? Container() ]); return tabBar;Copy the code
Case try
Small dishes try to add two fixed ICONS in the navigation bar under the two states of isScrollable or not;
_tabBar05(type, isLeft, isRight, {isScrollable}) => ACETabBar( isScrollable: isScrollable ?? true, alignType: ACETabBarAlignType.left, startIcon: isLeft ? Symmetric (Horizontal: 10.0), Child: FlutterLogo()) : NULL, endIcon: isRight? GestureDetector( onTap: () => print('----endIcon.click----'), child: Padding( padding: EdgeInsets.symmetric(horizontal: 10.0), Child: Icon(Icons. Add, color: colors.white)) : null, Controller: type == 0? _tabController : _tabController2, tabs: type == 0 ? _tabData02 : _tabData04); _tabBarWid07() => Container(height: 200.0, child: Scaffold(appBar: appBar (title: Text('true & LeftIcon & RightIcon'), bottom: _tabBar05(1, true, true)), body: _tabBarView(1))); _tabBarWid08() => Container(height: 200.0, child: Scaffold(appBar: appBar (title: Text('false & LeftIcon & RightIcon'), bottom: _tabBar05(1, true, true, isScrollable: false)), body: _tabBarView(1)));Copy the code
A small extension
In the process of understanding TabBar source code, xiao CAI simply learned Tab Item and corresponding indicator label drawing and corresponding sliding process; The PreferredSizeWidget widget is used during TabBar drawing.
The PreferredSizeWidget widget is an abstract interface class that returns the desired size of the widget without other restrictions. If the height is not constrained, the height specified by the PreferredSizeWidget is used. TabBar uses the preferredSize method to set the TabBar height.
@override Size get preferredSize { for (final Widget item in tabs) { if (item is Tab) { final Tab tab = item; if ((tab.text ! = null || tab.child ! = null) && tab.icon ! = null) return Size.fromHeight(_kTextAndIconTabHeight + indicatorWeight); }} return size. fromHeight(_kTabHeight + indicatorWeight -50.0); }Copy the code
ACETabBar case source code
Source: Little Monk A Ce