HarmonyOS Next实战教程:实现中间凹陷的异形tabbar

news/2025/3/16 7:16:42/文章来源:https://www.cnblogs.com/youlanjihua/p/18774506

今天要和大家分享的实战案例是实现中间凹陷的tabar

 

 

前些天在做墨迹天气的时候看到了这种异形的tabbar,看起来比较有挑战性,因为鸿蒙版的墨迹天气app还没有这个东西,我决定尝试做一下。

系统的Tabs肯定是不行了,我们需要自定义。

难度直接拉满,直接做最难的部分,就是这个中间有凹陷的矩形,这怎么整呢?

 

 

我们一点一点来,先不管矩形,先尝试画一条上边的曲线,这里需要使用三次贝塞尔曲线路径方法bezierCurveTo。

要画贝塞尔曲线,就要知道线上的坐标,尤其是曲线部分,坐标越多越好。

那么问题来了,直线部分的坐标很容易知道,曲线部分的坐标是多少呢?

我们需要做一道几何题,看一下这个曲线,它像是一个半圆又不像是一个半圆。我把它分解了一下,可以看到它是由三个同样大小的圆的三个部分拼凑起来,这三个圆的排列也比较有规律。

 

 

我们根据笛卡尔坐标系,计算出圆上的坐标点,越多越好。

我把这段曲线分为相等的4段,每一段都获取24个坐标点:

//精确度
let accuracy = 24
let finalP:Point[] = []
for (let index = 0;  index <=  j1_x; index+=(j1_x/accuracy)) {let pp = this.calculateYFromX(circle1.x,circle1.y,circleR,start_left_x + index,true)finalP.push(pp)
}
for (let index = j1_x;  index <=  middleSize/2 + j1_x; index+=(j1_x/(accuracy*2))) {let pp = this.calculateYFromX(circle2.x,circle2.y,circleR,start_left_x + index,false)finalP.push(pp)
}
for (let index = middleSize/2  + j1_x;  index <=  middleSize; index+=(j1_x/accuracy)) {let pp = this.calculateYFromX(circle3.x,circle3.y,circleR,start_left_x + index,true)finalP.push(pp)
}

 

这样曲线部分的坐标就有了。

现在我们开始画线,先画左边的直线:

@State padding_top:number = 6
this.context.lineTo(start_left_x,this.padding_top)

 

这里说一下y坐标为什么不是0,因为这个tabbar上方还有一些阴影,要把阴影这一部分留出来。

再画曲线部分:

for(let i = 1;i < finalP.length - 2;i+=3){this.context.bezierCurveTo(finalP[i].x,finalP[i].y,finalP[i+1].x,finalP[i+1].y,finalP[i+2].x,finalP[i+2].y,);
}

 

再画右边的直线:

this.context.lineTo(this.screen_width,this.padding_top)

 

同样的把其他三个边也都画线形成闭环。

接下来我们就可以进行填充:

this.context.fillStyle = '#ffffff'
this.context.stroke();
this.context.fill()

 

刚才说了tabbar有阴影,很多同学不知道贝塞尔曲线可以设置阴影,下面给大家示范一下:

this.context.shadowOffsetY = 0
this.context.shadowColor = '#949494'
this.context.shadowBlur = 12
this.context.stroke();

 

这样就实现了沿着曲线的阴影,非常完美。

现在我们要在画布上添加切换页面的按钮,很明显要使用层叠布局,而且中间的按钮要给它特殊处理一下

@State tabList:TabItem[] = [{image:$r('app.media.tb00'),selectImage:$r('app.media.tb01'),title:'首页'},{image:$r('app.media.tb10'),selectImage:$r('app.media.tb11'),title:'发现'}
]
ForEach(this.tabItems,(item:TabItem,index)=>{if(index == this.tabItems.length/2){Image($r('app.media.middle')).width(60).height(60).borderRadius(30).offset({y:-30}).borderWidth(4).borderColor(Color.White).borderStyle(BorderStyle.Solid).shadow({radius: 20,color: Color.Gray,offsetX: 0,offsetY: 0}).onClick(()=>{this.currentIndex = indexthis.tabClick(-1)})}Column({space:4}){Image(this.currentIndex == index? item.selectImage:item.image).width(22).height(22).objectFit(ImageFit.Contain)Text(item.title).fontSize(13).fontColor( this.currentIndex == index? this.selectedFontColor:this.fontColor)}.alignItems(HorizontalAlign.Center).onClick(()=>{this.currentIndex = indexthis.tabClick(index)})// .backgroundColor(Color.Black)
})

 

现在一个完整的tabbar样式就完成了,接下来要用它替换系统的tabbar并且实现页面的切换,虽然说是替换掉系统tabbar,但是还是要使用它。你会发现在系统的tabbar中不设置tabBar属性的话页面底部就会是一片空白:

 

 

正好可以将我们的tabbar放在那,你还可以使用barHeight属性调整高度:

Stack({alignContent:Alignment.Bottom}){Tabs({ barPosition: BarPosition.End, controller: this.tabsController }) {TabContent() {Page1()}TabContent() {Page2()}TabContent() {Page3()}TabContent() {Page3()}}.backgroundColor(Color.White).barHeight(64).onChange((index) => {this.currentIndex = index}).animationDuration(1).scrollable(false)BottomBar({tabItems:this.tabList,currentIndex:this.currentIndex,tabClick:(index)=>{if(index == -1){router.pushUrl({url:'pages/Page3'})}else {this.tabsController.changeIndex(index)}}})
}
.height('100%')
.width('100%')

 

这样我们就成功实现了异形的自定义tabbar,非常完美。

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

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

相关文章

HarmonyOS NEXT实战:高仿墨迹天气开发手记(附源码)

老余说3月份的神秘产品是为纯血鸿蒙而生的一款全新形态的手机,别人想象不到的手机产品,这次的保密工作真是非常到位,让人十分期待。 闲言少叙,今天为大家分享新年的第一个实战项目,高仿墨迹天气 这个项目中有一些复杂的动效和曲线,对于新手友友来说可能会有一点难,不过没…

VSCode + CMake + MinGW 在 Windows 下的简易调试指南

VSCode + CMake + MinGW 在 Windows 下的简易调试指南 目录VSCode + CMake + MinGW 在 Windows 下的简易调试指南准备工作下载VSCode下载CMake下载MinGW待编译源码VSCode调试task.json 配置launch.json 配置开始调试鉴于网络上关于VSCode的调试的教程不多,并且掺杂着大量的随机…

指令集并行与开发进阶算法

进阶算法 基础算法无法解决中断恢复的问题,即假如有两个写寄存器的操作,指令1,指令2,可能乱序执行时指令2的结果已经将写回了寄存器,但是指令1还未执行,此时发生中断后,从指令1重新开始执行,就会重新进行两次写入,将会发生错误。 只要保证后面指令修改机器状态时, 前面…

指令集并行与开发Tomasulo算法

指令集并行与开发Tomasulo算法 1. 概念 Tomasulo 方法是一种用于在超标量处理器中执行指令并处理数据相关(数据相关性)的方法。它主要通过对指令进行乱序执行和动态调度来提高指令级并行性。 可以通过寄存器重命名消除 WAR 和 WAW 相关(通过保留站号间接实现重命名) 也可以…

芯片存储器层次结构概述

存储器层次结构概述 1. Cache的作用 Cache结构与作用,如图2-5所示。图2-5 Cache结构与作用 介绍一下Cache具有特征。Cache没有程序上的意义,只是为了降低访存延迟;处理器访问Cache和访问存储器使用相同的地址。 Tag存储cache块在主存中的首地址(cache每个字节都给一个地址太…

推荐1《AI芯片开发核心技术详解》、2《智能汽车传感器:原理设计应用》、3《TVM编译器原理与实践》、4《LLVM编译器原理与实践》书,谢谢

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

MYSQL-DDL操作

点击查看代码 ```plaintext create table tb(id int comment ID,username varchar(20) comment 用户名,name varchar(10) comment 姓名,age int comment 年龄,gender char(1) comment 性别 )comment user测试表</details> ![](https://img2024.cnblogs.com/blog/3619156…

JetBrains IDEA破解后一直跳出激活弹窗

正文 一直跳弹窗是因为选了区域中国,你可以断网,然后到打开设置,搜索区域,选择亚洲。保险起见,保存后先关闭idea,再连接网络,启动IDEA。

三分钟教学:手把手教你实现Arduino发布第三方库

Arduino 发布第三方库的流程包括:构建库的基本框架后将其打包并上传至 GitHub,在 GitHub 上创建 Tag 和 Release 后,提交到 Arduino 库管理器,最后在Arduino IDE进行验证。三分钟教学:手把手教你实现Arduino发布第三方库原文链接: 手把手教你实现Arduino发布第三方库 摘要…

2025-315晚会总结

🔖简介 2025年315晚会曝光了多个行业的消费乱象和违法侵权行为。 主题:“共铸诚信 提振消费”,聚焦食品安全、公共安全、金融安全、数字经济等领域。 核心诉求:打击消费陷阱,推动构建公平、诚信的消费环境。 📢曝光现象 🔒数据安全与隐私侵权非法窃取个人信息涉事企业…

再破难关(BFS)

问题 F: 再破难关 题目描述 OIBH组织派出的黄金十二人+青铜五小强还没有到, 他们只能指望原先的机关能够阻拦住柯南的脚步。柯南打开大门之后发现里面还有一个门, 门上还有一个神奇的锁(-,-) 这是一个4*4的锁, 上面有8个凸起的格子和8个被按下的格子,当且仅当两个格子有公共边…

LLM大模型:OpenManus原理

继deepseek之后,武汉一个开发monica的团队又开发了manus,号称是全球第一个通用的agent!各路自媒体企图复刻下一个deepseek,疯狂报道!然而manus发布后不久,metaGPT团队5个工程师号称耗时3小时就搞定了一个demo版本的manus,取名openManus,才几天时间就收获了34.4K的start…