Flutter 126: 图解自定义两侧对齐 ACETabBar 标签导航栏
小菜在实践学习过程中,需要把 TabBar 标签栏默认居左,而 TabBar 默认是居中状态;小菜借此机会学习一下 TabBar 源码,稍微调整一下对齐方式;
ACETabBar
ACETabBarAlignType 对齐方式
小菜添加了一个 alignType 用于设置 ACETabBar 对齐方式;同时设置 isScrollable = true;当 isScrollable = false 时与 TabBar 默认占满屏幕均分效果一致;
(福利推荐:阿里云、腾讯云、华为云服务器最新限时优惠活动,云服务器1核2G仅88元/年、2核4G仅698元/3年,点击这里立即抢购>>>)
enum ACETabBarAlignType { left, center, right }
源码分析
小菜分析 TabBar 源码,在 _TabBarState 中 TabBar 绘制过程中,多个子 Tab 通过 SingleChildScrollView 存放,最简单的方式,在 SingleChildScrollView 外添加可以设置对齐方式的 Container 即可;
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); }
案例尝试
小菜尝试了在 isScrollable 是否可滑动两种状态下,ACETabBar 的对齐方式;
_tabBar01() => ACETabBar( isScrollable: true, controller: _tabController, tabs: <Widget>[ Tab(text: '今日', icon: Icon(Icons.account_circle)), Tab(text: '今日爆款土货生鲜'), Tab(text: '分类') ]); _tabBar02() => ACETabBar( isScrollable: true, alignType: ACETabBarAlignType.left, controller: _tabController, tabs: <Widget>[ Tab(text: '今日爆款'), Tab(text: '今日爆款土货生鲜'), Tab(text: '分类') ]); _tabBar03() => ACETabBar( isScrollable: true, alignType: ACETabBarAlignType.right, controller: _tabController, tabs: <Widget>[ Tab(text: '今日爆款'), Tab(text: '今日爆款土货生鲜'), Tab(text: '分类') ]); _tabBar04() => ACETabBar( isScrollable: false, alignType: ACETabBarAlignType.right, controller: _tabController, tabs: <Widget>[ Tab(text: '今日爆款'), Tab(text: '今日爆款土货生鲜'), Tab(text: '分类') ]);
startIcon & endIcon 固定位图标
类似很多新闻类或商城类 app,在 TabBar 所在的左右两侧通常会有固定的图标或文字等小 Widget;而小菜也在设置完对齐方式后增加了 startIcon & endIcon 两个图标位;
源码分析
小菜在设置对齐方式的时了解到 _TabBarState 用于绘制展示是否可滑动的 TabBar,小菜增加两个 startIcon & endIcon 两个属性,在最终 return tabBar 时进行判断是否展示添加到导航栏中;而是否添加点击事件可以通过添加 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;
案例尝试
小菜尝试在 isScrollable 是否可滑动两种状态下,在导航栏中添加左右两个固定位图标;
_tabBar05(type, isLeft, isRight, {isScrollable}) => ACETabBar( isScrollable: isScrollable ?? true, alignType: ACETabBarAlignType.left, startIcon: isLeft ? Padding( padding: EdgeInsets.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)));
小扩展
小菜在了解 TabBar 源码过程中,简单学习了 Tab Item 以及对应 indicator 标签指标的绘制及对应的滑动过程;其中在 TabBar 绘制过程中会用到 PreferredSizeWidget 小组件;
PreferredSizeWidget 小组件作为一个抽象接口类,主要用于返回该小部件在不受其他限制的情况下设定的较理想的大小;若没有进行约束高度,则会使用 PreferredSizeWidget 指定的高度;而 TabBar 就是实现了 preferredSize 方法,用于设置高度,小菜尝试调整 preferredSize 即可调整 TabBar 默认高度;
@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); }
ACETabBar 案例源码
来源: 阿策小和尚
你还在原价购买阿里云、腾讯云、华为云、天翼云产品?那就亏大啦!现在申请成为四大品牌云厂商VIP用户,可以3折优惠价购买云服务器等云产品,并且可享四大云服务商产品终身VIP优惠价,还等什么?赶紧点击下面对应链接免费申请VIP客户吧:
相关文章
- 专注效率提升「GitHub 热点速览 v.22.36」
- Git + Jenkins 自动化 NGINX 发布简易实现
- Caddy-用Go写的新一代可扩展WebServer
- 将git仓库从submodule转换为subtree
- 容器开发运维人员的 Linux 操作机配置优化建议
- 《前端运维》一、Linux基础--12网络
- 《前端运维》一、Linux基础--11服务
- 《前端运维》一、Linux基础--10定时任务
- 《前端运维》一、Linux基础--08Shell其他及补充
- 《前端运维》一、Linux基础--09常用软件安装
- 《前端运维》一、Linux基础--07Shell函数
- 《前端运维》一、Linux基础--06Shell流程控制
- 《前端运维》一、Linux基础--05Shell运算符
- 在Visual Studio 中使用git系列文章目录
- 《前端运维》一、Linux基础--04Shell变量
- 《前端运维》一、Linux基础--03Shell基础及补充
- 《前端运维》一、Linux基础--02用户与权限
- 《前端运维》一、Linux基础--01基础命令与vim
- 在Visual Studio 中使用git——同步到远程服务器-下(十二)
- 在Visual Studio 中使用git——同步到远程服务器-上(十一)