flutter 手写 TabBar

news/2024/9/14 5:56:58/ 标签: flutter, 前端

前言:

这几天在使用 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.ppmy.cn/news/1475914.html

相关文章

【Godot4.2】MLTag类:HTML、XML通用标签类

概述 HTML和XML采用类似的标签形式。 之前在Godot中以函数库形式实现了网页标签和内容生成。能用&#xff0c;但是缺点也很明显。函数之间没有从属关系&#xff0c;但是多有依赖&#xff0c;而且没有划分出各种对象和类型。 如果以完全的面向对象形式来设计标签类或者元素类…

信创终端系统上使用Pillow库调整图片大小 | 统信 | 麒麟 | 中科方德

原文链接&#xff1a;信创终端系统上使用Pillow库调整图片大小 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在信创终端系统上使用Pillow库调整图片大小的文章。Pillow是Python Imaging Library&#xff08;PIL&#xff09;的一个分支&#xff0c;是一个非常强…

【Git 学习笔记】第五章 在 Git 仓库存入附加信息(上)

第五章 在 Git 仓库存入附加信息 相关主题 添加第一条 Git 笔记按类别区分 Git 笔记从远程库读取 Git 笔记推送 Git 笔记到远程库为 commit 版本添加标签 Git 最强大的一个特性&#xff0c;在于它的提交历史 永不可改变。这意味着任何试图篡改仓库历史的行为&#xff0c;对于其…

排序-java(详解)

一&#xff0c;分类 主要的排序大致分为以下几类&#xff1a; 1&#xff0c;插入排序&#xff0c;又分为直接插入排序和希尔排序 2&#xff0c;选择排序&#xff0c;又分为选择排序和堆排序 3&#xff0c;交换排序&#xff0c;又分为冒泡排序和快速排序 4&#xff0c;归并…

论文翻译:通过云计算对联网多智能体系统进行预测控制

通过云计算对联网多智能体系统进行预测控制 文章目录 通过云计算对联网多智能体系统进行预测控制摘要前言通过云计算实现联网的多智能体控制系统网络化多智能体系统的云预测控制器设计云预测控制系统的稳定性和一致性分析例子结论 摘要 本文研究了基于云计算的网络化多智能体预…

第九课:服务器发布(静态nat配置)

一个要用到静态NAT的场景&#xff0c;当内网有一台服务器server1&#xff0c;假如一个用户在外网&#xff0c;从外网访问内网怎么访问呢&#xff0c;无法访问&#xff0c;这是因为外网没办法直接访问内网&#xff0c;这时候需要给服务器做一个静态NAT。 静态NAT指的是给服务器…

Html_Css问答集(8)

52、在网页设计中有一个目录assets一般表示什么意思 "Assets" 的英文原意是 资产。 在网页设计中&#xff0c;我们使用 "assets" 文件夹来存放网站的静态资源文件&#xff0c;就像把这些资源看作是网站的“资产”一样。 assets 文件夹中的静态资源…

使用Spring Boot实现分布式配置管理

使用Spring Boot实现分布式配置管理 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. 什么是分布式配置管理&#xff1f; 在分布式系统中&#xff0c;配置管理是一项重要的任务。它涉及到管理和集…

N叉树的前序遍历

Problem: 589. N 叉树的前序遍历 文章目录 思路解题过程Code 思路 前序遍历&#xff0c;遇到空节点返回 解题过程 对每个节点进行遍历 Code /* // Definition for a Node. class Node { public:int val;vector<Node*> children;Node() {}Node(int _val) {val _val;}Nod…

Nature Pixels V2 | Top-down pixel art asset pack

Nature Pixels V2可以用于自上而下的视图游戏&#xff0c;使其看起来更好&#xff01; 如果你喜欢这个资产包&#xff0c;一定要在评论中告诉我&#xff01;祝你今天过得愉快 所容纳之物 16x16瓷砖&#xff0c;可以帮助你用100多块瓷砖构建自己的美丽世界 房屋 岩石 树 墙壁 水…

Java(二十)---双向链表

文章目录 前言1.为什么学习双向链表2.双向链表(LinkedList)的模拟实现2.1. 准备工作2.2.功能的实现2.2.1.显示链表(display) 和 是否包含某种元素(contains) 以及 获取链表节点个数(size())2.2.2.头插法(addFirst)&#xff0c;尾插法(addLast)&#xff0c;以及在指定位置进行插…

RK3568 V1.4.0 SDK,USB OTG端子不能被电脑识别出adb设备,解决

修改后的/usr/bin/usbdevice: #!/bin/sh # # Usage: # usbdevice [start|update|stop] # # Hookable stages: # usb_<pre|post>_<init|prepare|start|stop|restart>_hook # <usb function>_<pre|post>_<prepare|start|stop>_hook # # Example …

第三方配件也能适配苹果了,iOS 18与iPadOS 18将支持快速配对

苹果公司以其对用户体验的不懈追求和对创新技术的不断探索而闻名。随着iOS 18和iPadOS 18的发布&#xff0c;苹果再次证明了其在移动操作系统领域的领先地位。 最新系统版本中的一项引人注目的功能&#xff0c;便是对蓝牙和Wi-Fi配件的配对方式进行了重大改进&#xff0c;不仅…

【LabVIEW学习篇 - 6】:数组、簇

文章目录 数组创建数组数组函数数组大小 根据索引取值数组与for循环 案例一案例二 簇LabVIEW簇的特点和用途&#xff1a;创建簇解除捆绑按名称解除捆绑簇的捆绑重新排序簇中控件 数组 在LabVIEW中&#xff0c;数组是一种用于存储相同数据类型的多个元素的数据结构。以下是关于…

技术探索之kotlin浅谈

Kotlin是一种静态类型编程语言&#xff0c;它运行在Java虚拟机&#xff08;JVM&#xff09;上&#xff0c;可以与Java代码互操作。Kotlin由JetBrains开发&#xff0c;是一种现代、简洁且安全的编程语言。它在2011年首次亮相&#xff0c;2017年被谷歌宣布为Android官方开发语言。…

作业7.16

第一题&#xff1a; 在终端的界面上输出:__-__-__-__ 1秒过后&#xff0c; 变成 1_-__-__-__ 再1秒过后&#xff0c;变成 12-__-__-__ 依此类推 经过8秒&#xff0c;最终变成 12-34-56-78 \b 是printf里面&#xff0c;光标向左移动的转义符 #include <stdio.h> #include …

视频使用操作说明书-T80004系列视频编码器如何对接海康NVR硬盘录像机,包括T80004系列高清HDMI编码器、4K超高清HDMI编码器

视频使用操作说明书-T80004系列视频编码器如何对接海康NVR硬盘录像机&#xff0c;包括T80004系列高清HDMI编码器、4K超高清HDMI编码器。 视频使用操作说明书-T80004系列视频编码器如何对接海康NVR硬盘录像机(不带屏)&#xff0c;包括T80004系列高清HDMI编码器、4K超高清HDMI编码…

hid.dll丢失怎么办?hid.dll丢失解决步骤分享

hid.dll&#xff0c;即Human Interface Device Dynamic Link Library&#xff0c;是Windows操作系统中用于管理人机交互设备&#xff08;HID&#xff09;的核心组件。这些设备包括但不限于键盘、鼠标、游戏控制器等。该DLL文件确保这些设备能够与操作系统顺畅通信&#xff0c;实…

ECCV`24 | 编辑能力无上限!北航谷歌旷视等开源Chat-Edit-3D: 3D 场景编辑新范式!

文章链接&#xff1a;https://arxiv.org/abs/2407.06842 项目地址&#xff1a;https://sk-fun.fun/CE3D/ 代码&#xff1a;https://github.com/Fangkang515/CE3D/tree/main 引言 过去的3D场景编辑方法往往局限于固定的文本输入模式和有限的编辑能力。用户需要学习特定的命令或…

前端打包部署后源码安全问题总结

随着现代Web应用越来越依赖于客户端技术&#xff0c;前端安全问题也随之突显。源码泄露是一个严重的安全问题&#xff0c;它不仅暴露了应用的内部逻辑和业务关键信息&#xff0c;还可能导致更广泛的安全风险。本文将详细介绍源码泄露的潜在风险&#xff0c;并提供一系列策略和工…