今天要和大家分享的实战案例是实现中间凹陷的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 = index
this.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 = index
this.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,非常完美。

HarmonyOS Next实战教程:实现中间凹陷的异形tabbar的更多相关文章

  1. 【ASP.NET实战教程】ASP.NET实战教程大集合,各种项目实战集合

    [ASP.NET实战教程]ASP.NET实战教程大集合,各种项目实战集合,希望大家可以好好学习教程中,有的比较老了,但是一直很经典!!!!论坛中很多小伙伴说.net没有实战教程学习,所以小编连夜搜集整 ...

  2. 【转】mybatis实战教程(mybatis in action),mybatis入门到精通

    MyBatis 目录(?)[-] mybatis实战教程mybatis in action之一开发环境搭建 mybatis实战教程mybatis in action之二以接口的方式编程 mybatis ...

  3. NDK-JNI实战教程(二) JNI官方中文资料

    声明 设计概述 JNI接口函数和指针 加载和链接本地方法 解析本地方法名 本地方法的参数 引用Java对象 全局和局部引用 实现局部引用 访问Java对象 访问基本类型数组 访问域和方法 报告编程错误 ...

  4. mybatis实战教程(mybatis in action),mybatis入门到精通

    转自:http://www.yihaomen.com/article/java/302.htm (读者注:其实这个应该叫做很基础的入门一下下,如果你看过hibernate了那这个就非常的简单) (再加 ...

  5. ActiveReports 9实战教程(3): 图文并茂的报表形式

    基于上面2节内容,我们搭建了AR9的开发环境,配置好了数据源.在本节,我们以官方提供的3个中文图文并茂的报表来展示AR9的功能,并通过实战的方式一一分享. 以往做报表相关的工作时,最害怕的是报表的UI ...

  6. 《软件性能测试与LoadRunner实战教程》新书上市

    作者前三本书<软件性能测试与LoadRunner实战>.<精通软件性能测试与LoadRunner实战>和<精通软件性能测试与LoadRunner最佳实战>面市后,受 ...

  7. BI之SSAS完整实战教程7 -- 设计维度、细化维度中 :浏览维度,细化维度

    上篇文章我们已经将Dim Geography维度设计好. 若要查看维度的成员, AS需要接收该维度的详细信息(包括已创建的特性.成员属性以及多级层次结构), 通过XMLA与AS的实例进行通信. 今天我 ...

  8. BI之SSAS完整实战教程6 -- 设计维度、细化维度上:创建维度定义特性关系

    前面我们使用过数据源向导.数据源视图向导.Cube向导来创建相应的对象. 本篇我们将学习使用维度向导来创建维度. 通过前面几个向导的学习,我们归纳一下共同点,主要分成两步 1. 使用某种对象类型的向导 ...

  9. BI之SSAS完整实战教程5 -- 详解多维数据集结构

    之前简单介绍过多维数据集(Cube)的结构. 原来计划将Cube结构这部分内容打散,在实验中穿插讲解, 考虑到结构之间不同的部分都有联系,如果打散了将反而不好理解,还是直接一次性全部讲完. 本篇我们将 ...

  10. BI之SSAS完整实战教程4 -- 部署至SSAS进行简单分析

    上一篇已经创建了多维数据集的结构. 接下来我们将多维数据集的架构定义发送到Analysis Services实例,部署到AS上去. 文章提纲 部署和浏览多维数据集 SSMS使用简介 总结 一.部署和浏 ...

随机推荐

  1. Vue3 数据响应式原理与高效数据操作全解析

    一.Vue3 数据响应式原理 (一)Proxy 替代 Object.defineProperty 在 Vue2 中,数据响应式是通过 Object.defineProperty 实现的.这种方法虽然能 ...

  2. Javascript 显示当前滚动条滚动的百分比

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. hbase - [03] 客户端常用命令(hbase shell)

    1.列出所有namespace list_namespace 2.创建namespace create_namespace 'ns_name' 3.修改namespace属性 alter_namesp ...

  4. linux安装lspci

    点击查看代码 `lspci` 是一个用于在Linux系统中显示所有PCI总线以及已连接设备信息的命令.这个工具通常包含在 `pciutils` 包里.如果你需要在你的Linux系统上安装 `lspci ...

  5. pandas 操作excel

    一 Series 什么是series 相当于表格中的行和列,不同的设置可以按行或列排序 2.series 创建 空的series import pandas as pd s2=pd.Series() ...

  6. Java 线程安全的集合

    Vector ArrayList 的线程安全版本,对所有的修改方法都进行了 synchronized 同步处理.适用于多线程环境下对数据一致性要求高,且读写操作相对比较均衡,不需要很高并发性能的场景. ...

  7. centos操作collection

    Centos修改IP地址 https://blog.csdn.net/weixin_45193791/article/details/124646170 Centos打开.修改.保存文件 https: ...

  8. oracle中查看锁表,ORACLE中查看当前系统中锁表情况

    1.ORACLE中查看当前系统中锁表情况 select * from v$locked_object 2.可以通过查询v$locked_object拿到sid和objectid,然后用sid和v$se ...

  9. 事件监听、焦点--java进阶day03

    1.事件 按钮是组件,点击后就会重新游戏 对于这种点击了组件之后,有逻辑触发的操作,就是事件 2.事件中的专有名词 绑定监听也就是绑定监视,是真正组织代码逻辑的地方 要有绑定监听就需要监听器,今天学习 ...

  10. 【SpringCloud】Gateway新一代网关

    Gateway新一代网关 概述简介 官网 上一代zuul 1.x https://github.com/Netflix/zuul/wiki 当前gateway https://cloud.spring ...