flutter 手写 TabBar

前言:

这几天在使用 flutter TabBar 的时候 我们的设计给我提了一个需求:

如下 Tabbar  第一个元素 左对齐试了下TabBar 的配置,无法实现这个需求,他的 配置是针对所有元素的。而且 这个 TabBar 下面的 滑块在移动的时候 上面的文字会相应的抖动。

看了下 TabBar 的源代码 他的实现是相对复杂的 下面的 滑块是 canvas 实现的。 有可能他要实现的功能比较丰富。

自定义Tabbar 的基本布局

下面是我页面的布局:这样实现起来 里面元素的 样式可以完全自己定义单个配置,想怎么显示都可以。这样就可以不用局限于 自带Tabbar的配置

SingleChildScrollView 解析

完成页面布局相对简单,主要实现底部 滑块的移动,以及 整 SingleChildScrollView 的居中移动是一个关键点

ScrollController 中的几个关键概念:
  • controller.position.viewportDimension:  SingleChildScrollView 视口 的大小
  • position.maxScrollExtent :                     SingleChildScrollView 可以移动的最大范围
  • position.minScrollExtent  :                     SingleChildScrollView 可以移动最小范围 一般是0
  • Row 的长度就是所有元素的长度之和:也就是 position.maxScrollExtent + position.viewportDimension 

Row 的长度之和 为什么是 SingleChildScrollView 最大可移动范围加 position.viewportDimension 的和

SingleChildScrollView 可见区域始终是他的视口大小,不可见的也就是 Row的长度减去视口大小 也就是 maxScrollExtent 可拖动的最大区域

实现 Tabbar

下面是我实现的大致效果:第一个元素左对齐,最后一个元素右对齐,我这边是直接写死的,你们封装一下 在外边直接用就好了。

代码如下:

import 'dart:ui';import 'package:flutter/material.dart';
import 'package:game/const/app_textStyle.dart';
import 'package:game/utils/app_widget.dart';
import 'package:game/wrap/extension/extension.dart';class PageTabBar extends StatefulWidget {const PageTabBar({Key? key}) : super(key: key);@overrideState<PageTabBar> createState() => _PageTabBarState();
}class _PageTabBarState extends State<PageTabBar> {final ScrollController _controller = ScrollController();int _selectIndex = 0;double _width = 0;double _positionX = 0;final List<Map> _listMap = [{'width': 0, 'name': '一号', 'key': GlobalKey()},{'width': 0, 'name': '二二号技师', 'key': GlobalKey()},{'width': 0, 'name': '三三三号技师', 'key': GlobalKey()},{'width': 0, 'name': '四号技师', 'key': GlobalKey()},{'width': 0, 'name': '五五号技师', 'key': GlobalKey()},{'width': 0, 'name': '六六六号技师', 'key': GlobalKey()},{'width': 0, 'name': '七号技师', 'key': GlobalKey()},{'width': 0, 'name': '八八号技师', 'key': GlobalKey()},{'width': 0, 'name': '九', 'key': GlobalKey()},{'width': 0, 'name': '十号技师', 'key': GlobalKey()},];@overridevoid initState() {// TODO: implement initStatesuper.initState();WidgetsBinding.instance.addPostFrameCallback((_) => _printSize());// _controller.addListener(() {//   print('_controller.offset:${_controller.offset}');// });}@overridevoid dispose() {// TODO: implement dispose_controller.dispose();super.dispose();}void _printSize() {for (Map element in _listMap) {final RenderBox box = element['key'].currentContext.findRenderObject();element['width'] = box.size.width;}_width = _listMap[0]['width'];_selectItem(0);}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppWidget.appBar(title: 'TabBar 测试页面'),body: Center(child: Container(height: 220.cale,width: 710.cale,color: Colors.deepOrangeAccent,child: SingleChildScrollView(physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics(),),controller: _controller,scrollDirection: Axis.horizontal,child: Stack(children: [Row(children: _listMap.asMap().map((key, value) => MapEntry(key,AppWidget.inkWellEffectNone(onTap: () {_selectItem(key);},child: Container(padding: key == 0? EdgeInsets.only(right: 25.cale): key == _listMap.length - 1? EdgeInsets.only(left: 25.cale): EdgeInsets.symmetric(horizontal: 25.cale),key: value['key'],color: Colors.blue.withOpacity(0.1 * key),height: 180.cale,child: Center(child: Text(value['name'],style: _selectIndex == key? AppTextStyle.textStyle_34_FD3949_Bold: AppTextStyle.textStyle_30_1A1A1A,),),),),),).values.toList(),),AnimatedPositioned(bottom: 0.cale,left: _positionX,duration: const Duration(milliseconds: 250),child: AnimatedContainer(duration: const Duration(milliseconds: 250),width: _width,child: Container(height: 20.cale,margin: EdgeInsets.symmetric(horizontal: 25.cale),width: double.infinity,color: Colors.green,),),)],),),),),);}void _selectItem(int index) {print('index:$index');final ScrollPosition position = _controller.position;setState(() {_selectIndex = index;_width = _listMap[index]['width'];});_positionX = 0;List.generate(index, (itemIndex) {_positionX += _listMap[itemIndex]['width'];});//当前展示的元素位置 中心点位置,用户确定 滚动位置double viewPosition = _positionX + _listMap[index]['width'] / 2;double movePosition = viewPosition - position.viewportDimension / 2;movePosition = clampDouble(movePosition, position.minScrollExtent, position.maxScrollExtent);_controller.animateTo(movePosition,duration: const Duration(milliseconds: 300),curve: Curves.easeOut,);}
}

可以按需求封装下就能上手使用了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/378193.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea中使用maven

默认情况下&#xff0c;idea会自动下载并安装maven&#xff0c;这不便于我们管理。 最好是自行下载maven&#xff0c;然后在idea中指定maven的文件夹路径

解析 Mira :基于 Web3,让先进的 AI 技术易于访问和使用

“Mira 平台正在以 Web3 的方式解决当前 AI 开发面临的复杂性问题&#xff0c;同时保护 AI 贡献者的权益&#xff0c;让他们可以自主拥有并货币化自己的模型、数据和应用&#xff0c;以使先进的 AI 技术更加易于访问和使用。” AI 代表着一种先进的生产力&#xff0c;它通过深…

【UE5.1】NPC人工智能——02 NPC移动到指定位置

效果 步骤 1. 新建一个蓝图&#xff0c;父类选择“AI控制器” 这里命名为“BP_NPC_AIController”&#xff0c;表示专门用于控制NPC的AI控制器 2. 找到我们之前创建的所有NPC的父类“BP_NPC” 打开“BP_NPC”&#xff0c;在类默认值中&#xff0c;将“AI控制器类”一项设置为“…

影响转化率的多元因素分析及定制开发AI智能名片S2B2C商城系统小程序的应用案例

摘要&#xff1a;在互联网时代&#xff0c;转化率是衡量营销活动成功与否的关键指标。本文首先分析了影响转化率的多种因素&#xff0c;包括活动页面的设计、活动的限时性、主题文案的吸引力、从众心理的运用&#xff0c;以及最核心的产品质量与优惠力度。接着&#xff0c;本文…

path+HTTP协议+IP+端口(nodejs)

一.path //导入 fs const fs require(fs); const path require(path); //写入文件 // fs.writeFileSync(__dirname /index.html, love); // console.log(__dirname /index.html);//resolve 解决 // console.log(path.resolve(__dirname, ./index.html)); // console.log(p…

JVM知识点梳理

目录标题 1.类加载机制1.1 Java 运行时一个类是什么时候被加载的?1.2 JVM 一个类的加载过程?1.3 一个类被初始化的过程?1.4 继承时父子类的初始化顺序是怎样的?1.5 究竟什么是类加载器?1.6 JVM 有哪些类加载器?1.7 JVM 中不同的类加载器加载哪些文件?1.8 JVM 三层类加载…

基于LSTM及其变体的回归预测

1 所用模型 代码中用到了以下模型&#xff1a; 1. LSTM&#xff08;Long Short-Term Memory&#xff09;&#xff1a;长短时记忆网络&#xff0c;是一种特殊的RNN&#xff08;循环神经网络&#xff09;&#xff0c;能够解决传统RNN在处理长序列时出现的梯度消失或爆炸的问题。L…

动手学深度学习6.3 填充和步幅-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;填充和步幅_哔哩哔哩_bilibili 代码实现_哔哩哔哩_bilibili 本节教材地址&#xff1a;6.3. 填充和…

笔记 5 :linux 0.11 注释,函数 copy_mem() , copy_process () , 中断函数 int 80H 的代码框架

&#xff08;38&#xff09;接着介绍一个创建进程时的重要的函数 copy_mem&#xff08;&#xff09; 函数&#xff1a; &#xff08;39&#xff09; 分析另一个关于 fork&#xff08;&#xff09; 的重要的函数 copy_process&#xff08;&#xff09;&#xff0c;与李忠老师的操…

Qcom平台通过Hexagon IDE 测试程序性能指导

Qcom平台通过Hexagon IDE 测试程序性能指导 1 安装Hexagon IDE工具2 测试工程2.1 打开Hexagon IDE2.2 新建工程2.3 添加测试案例2.3.1 方法一&#xff1a;新建2.3.2 方法二&#xff1a;拷贝 2.4 配置测试环境2.4.1 包含头文件2.4.2 添加程序优化功能(需先bulid一下)2.4.3 添加g…

【问题记录】Docker配置mongodb副本集实现数据流实时获取

配置mongodb副本集实现数据流实时获取 前言操作步骤1. docker拉取mongodb镜像2. 连接mongo1镜像的mongosh3. 在mongosh中初始化副本集 注意点 前言 由于想用nodejs实现实时获取Mongodb数据流&#xff0c;但是报错显示需要有副本集的mongodb才能实现实时获取信息流&#xff0c;…

HTTPS请求头缺少HttpOnly和Secure属性解决方案

问题描述&#xff1a; 建立Filter拦截器类 package com.ruoyi.framework.security.filter;import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.…

某客户管理系统Oracle RAC节点异常重启问题详细分析记录

一、故障概述 某日10:58分左右客户管理系统数据库节点1所有实例异常重启&#xff0c;重启后业务恢复正常。经过分析发现&#xff0c;此次实例异常重启的是数据库节点1。 二、故障原因分析 1、数据库日志分析 从节点1的数据库日志来看&#xff0c;10:58:49的时候数据库进程开始…

1.MQ介绍

MQ 消息队列&#xff0c;本质是一个队列&#xff0c;先进先出&#xff0c;只不过队列中存放的内容是message而已。 为啥学习MQ 1.流量消峰 如果一个订单系统最多每秒能处理一万次订单&#xff0c;正常情况下我们下单1秒后就能返回结果。但是在高峰期&#xff0c;如果有两万…

Linux驱动开发笔记(十九)文件系统的构建

文章目录 前言一、文件系统1.1 Linux系统的组成1.2 什么是文件系统 二、根文件系统的制作工具三、busybox3.1 什么是busybox3.2 制作流程 四、buildroot4.1 什么是Buildroot4.2 制作流程 前言 上节我们在mdev实验进行配置时&#xff0c;利用了busybox&#xff0c;这里着重对这部…

活动预告|想更了解流式数据湖?亚马逊云科技数据开源软件-流式数据湖 Tech Talk来啦!

活动介绍 本次活动旨在探索在亚马逊云科技上构建和使用开源数据软件产品的一些最佳实践&#xff0c;特别关注流式数据湖的构建。活动将在线上举行&#xff0c;汇聚来自 AutoMQ Apache paimon和亚马逊云科技的顶尖专家&#xff0c;分享他们在这一领域的最新进展和实际经验。参与…

旗晟巡检机器人的应用场景有哪些?

巡检机器人作为现代科技的杰出成果&#xff0c;已广泛应用于各个关键场景。从危险的工业现场到至关重要的基础设施&#xff0c;它们的身影无处不在。它们以精准、高效、不知疲倦的特性&#xff0c;担当起保障生产、守护安全的重任&#xff0c;为行业发展注入新的活力。那么&…

2024华为数通HCIP-datacom最新题库(变题更新⑥)

请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 请注意&#xff0c;华为HCIP-Datacom考试831已变题 近期打算考HCIP的朋友注意了&#xff0c;如果你准备去考试&#xff0c;还是用的之前的题库&#xff0c;切记暂缓。 1、…

【Elasticsearch7】3-基本操作

目录 RESTful 数据格式 HTTP操作 索引操作 倒排索引 创建索引 查看所有索引 查看单个索引 删除索引 文档操作 创建文档 查看文档 ​编辑 全量修改 ​编辑局部修改 删除文档 条件删除文档 高级查询 条件查询 URL带参查询 请求体带参查询 带请求体方式的查…

使用GPT3.5,LangChain,FAISS和python构建一个本地知识库

引言 介绍本地知识库的概念和用途 在现代信息时代&#xff0c;我们面临着海量的数据和信息&#xff0c;如何有效地管理和利用这些信息成为一项重要的任务。本地知识库是一种基于本地存储的知识管理系统&#xff0c;旨在帮助用户收集、组织和检索大量的知识和信息。它允许用户…