场景介绍部分应用在使用过程中需要自定义添加或删除标签的场景,比如在浏览器中的顶部标签栏中需要新打开或关闭网页页签,而这种场景与tabs组件效果类似,但tabs组件不提供增加或删除页签的功能,不能自由的增加删除页签,需要开发者自己实现tabs中增删页签功能。本文以浏览器中增加或删除页签为例,实现tabs中页签的增删功能。
效果呈现如下动图所示:
环境要求本例基于以下环境开发,开发者也可以基于其他适配的版本进行开发:
ide: deveco studio 4.0 releasesdk: ohos_sdk_public 4.0.10.13 (api version 10 release)实现原理本例涉及的关键特性以及实现方案如下:
通过@builder自定义封装一个导航页签栏,并通过foreach完成对tabs组件的内容页和导航页签栏的动态渲染。通过tabscontroller的changeindex可实现页面的跳转,传入的index是数组中对应的索引值。页签的增加通过数组的push方法,增加数组元素。删除页签通过通过删除页面对应数组的索引值处的数据完成,删除后页面跳转位置根据业务逻辑要求确定跳转页面对应的索引值。开发步骤整体布局分为两部分:页面内容和页签部分。页面视图部分使用tabs,其中页签对应显示的内容需要放入tabcontent组件中。页签部分通过@builder自定义封装一个tabbar组件,放入tabs中的tabbar属性中。
页面视图代码块:
tabs({ barposition: barposition.start, controller: this.controller }) { foreach(this.tabarray, (item: number) = > { tabcontent() { text('我是页面 ' + item + 的内容) .height('100%') .width('100%') .fontsize(30) .backgroundcolor(#ffffffff) }.tabbar(this.tab(item)) }, (item: number) = > item.tostring() + util.generaterandomuuid())}.barmode(barmode.scrollable, { margin: 30 }).onchange((index) = > { this.focusindex = index}).barheight(30)自定义tabbar代码块:
//控制页签渲染的数组@state tabarray: array = [0]//tabs组件当前显示的页签@state focusindex: number = 0//创建页签时的页签index@state pre: number = -1//tabs组件控制器,根据组件下标控制tab跳转private controller: tabscontroller = new tabscontroller()//自定义导航页签栏@buildertab(tabnumber: number) { row({ space: 20 }) { text(页签 + tabnumber).fontsize(18) image($r('app.media.ic_public_cancel_filled')).width(20).height(20) } .justifycontent(flexalign.center) .constraintsize({ minwidth: 35 }) .width(120) .height(30) .borderradius({ topleft: 10, topright: 10 }) .backgroundcolor(this.tabarray.indexof(tabnumber) === this.focusindex ? #ffffffff : #ffb7b7b7)}实现页签和页面视图的联动:这里主要通过tabscontroller的changeindex来实现对应的试图跳转,但需要注意由于之后会增删数组元素的操作,所以此处传入的index值是选择页面的tabnumber在数组中的索引值。
this.focusindex = this.tabarray.indexof(tabnumber)增添数组元素实现增加页签的效果:增添数组元素使用数组的push方法在tabarray添加数据即可,但由于此demo原始定义的数组是连续的自然数,后续增删数组会打乱原有顺序,所以此处处理为先判断最后一个元素的值再加1,由于tabbar的渲染是通过foreach被@state修饰的数组,因此当tabarray中添加数据后系统会通知foreach便利数组重新渲染页面。
this.tabarray.push(this.tabarray[this.tabarray.length - 1] + 1)通常在添加新页面后,浏览器会将页面跳转到新添加的页面,因此在向tabarray中完成数据推送后,需要将页签通过tabscontroller中的changeindex方法跳转到最后一个。
this.focusindex = this.tabarray.length - 1this.controller.changeindex(this.focusindex)当用户选择另一个页签时,可通过自定义页签中通用事件onclick进行控制,当用户点击待选择的页签后,获取当前页签对应的下标,然后通过tabscontroller中的changeindex方法进行跳转,此外可以通过更改页签背景颜色标识被选中页签的。
.backgroundcolor(this.tabarray.indexof(tabnumber) === this.focusindex ? #ffffffff : #ffb7b7b7).onclick(() = > { this.focusindex = this.tabarray.indexof(tabnumber) this.controller.changeindex(this.focusindex)})删除页面有三种情况(删除不同位置的页面)。
第一种情况是被关闭页面为最后一个页面,且当前选中的页面为最后一个页面,如果当前被选中页面是刚刚被其他页面创建的情况,因此页面需要跳回到创建被删除页签的页签(逻辑参考chrome浏览器)
if (this.pre >= 0) { this.focusindex = this.pre} this.tabarray.splice(this.tabarray.indexof(tabnumber), 1)如果不是的话直接将当前显示页签下下标设置为前一个页签下标,tabarray数组通过splice方法删除页签,并通过tabscontroller完成跳转,此外页面只要有关闭操作,页面就不可以跳回打开该页面的页面,即将 pre设置为-1。
this.focusindex = this.focusindex - 1this.tabarray.splice(this.tabarray.indexof(tabnumber), 1)this.pre = -1this.controller.changeindex(this.focusindex)第二种情况,当用户当前选择的不是最后一个标签,然后直接删除其他页签时,可以直接删除删除,但是需要重新计算当前选中页签在tabarray中的实时位置,到新注意需要排除用户在最后一个页签删除当前页签的情况。
//当前选择页面的对应数组中的数据值let focusnumber = this.tabarray[this.focusindex]//用于判断是否是用户在最后一个页签删除当前页签的情况if (this.tabarray.indexof(focusnumber) >= 0) { this.focusindex = this.tabarray.indexof(focusnumber)}this.controller.changeindex(this.focusindex)第三种情况,当用户当前选择的不是最后一个标签,且删除被选中页面,直接删除,然后通过tabscontroller完成跳转,不需要额外操作。
说明
由于tabs组件中的导航页签栏会占满屏幕,导致添加按钮无法直接添加到与页签直接平齐的位置,因此通过层叠布局(stack)的方式,将添加页签按钮覆盖到tabs组件上,通过stack中的对齐方式将添加按钮调整到合适位置。用于tabs添加或删除子节点时,foreach需要重新将所有页签进行重新渲染,如果在添加或删除完页签后直接调用tabscontroller中的changeindex进行跳转,页面无法调到指定页签。这是由于foreach还未将组件渲染完成,将子组件挂载到tabs中,因此建议通过settimeout延迟一段时间再进行跳转,经过验证大概50ms后即可,开发者可再自行验证。settimeout(() = > { this.controller.changeindex(this.focusindex)}, 50)完整实例完整示例代码如下:
import util from '@ohos.util'@entry@componentstruct drag { //控制页签渲染的数组 @state tabarray: array = [0] //tabs组件当前显示的页签下标 @state focusindex: number = 0 //创建页签时的页签index @state pre: number = -1 //tabs组件控制器,根据组件下标控制tab跳转 private controller: tabscontroller = new tabscontroller() // 单独的页签 @builder tab(tabnumber: number) { row({ space: 20 }) { text(页签 + tabnumber).fontsize(18) image($r('app.media.ic_public_cancel_filled')).width(20).height(20).onclick(() = > { //获取tabs组件当前显示的页签中显示的数字 let focusnumber = this.tabarray[this.focusindex] //被删除的页签是否是当前选中的页签,且是最后一个页签 if (this.focusindex === this.tabarray.indexof(tabnumber) && this.focusindex == this.tabarray.length - 1) { //判断是否需要跳回到创建该页签时的页签,如果不需要直接跳转到前一个页签 if (this.pre >= 0) { this.focusindex = this.pre } else { this.focusindex = this.focusindex - 1 } } this.tabarray.splice(this.tabarray.indexof(tabnumber), 1) this.pre = -1 //对应删除页面中的第二种情况 if (this.tabarray.indexof(focusnumber) >= 0) { this.focusindex = this.tabarray.indexof(focusnumber) } //设置50ms 延迟跳转 settimeout(() = > { this.controller.changeindex(this.focusindex) }, 50) }) } .justifycontent(flexalign.center) .constraintsize({ minwidth: 35 }) .width(120) .height(30) .borderradius({ topleft: 10, topright: 10 }) .backgroundcolor(this.tabarray.indexof(tabnumber) === this.focusindex ? #ffffffff : #ffb7b7b7) .onclick(() = > { this.focusindex = this.tabarray.indexof(tabnumber) settimeout(() = > { this.controller.changeindex(this.focusindex) }, 50) }) } build() { column() { column() { // 页签 // row() { stack() { row({ space: 7 }) { //tabs tabs({ barposition: barposition.start, controller: this.controller }) { foreach(this.tabarray, (item: number) = > { tabcontent() { text('我是页面 ' + item + 的内容) .height('100%') .width('100%') .fontsize(30) .backgroundcolor(#ffffffff) }.tabbar(this.tab(item)) }, (item: number) = > item.tostring() + util.generaterandomuuid()) } .barmode(barmode.scrollable, { margin: 30 }) .onchange((index) = > { this.focusindex = index }) .barheight(30) }.width(100%) row() { image($r('app.media.ic_public_add_filled')).onclick(() = > { if (this.tabarray.length === 0) { this.tabarray.push(0) this.focusindex = this.tabarray.length - 1 } else { this.pre = this.focusindex this.tabarray.push(this.tabarray[this.tabarray.length - 1] + 1) this.focusindex = this.tabarray.length - 1 } settimeout(() = > { this.controller.changeindex(this.focusindex) }, 50) }).width(20).height(20) }.height(30).width(30).backgroundcolor(#ffb7b7b7) .justifycontent(flexalign.center) } .aligncontent(alignment.topend) .width('100%') .backgroundcolor(#ffb7b7b7) } .alignitems(horizontalalign.start) .width('100%') } .height('100%') }}本文主要讲解在鸿蒙开发当中arkui中的增删tab页签实现,更多的鸿蒙arkui学习,可以参考下面的学习曲线图:
完整版鸿蒙os与openharmony技术路线与文档,可在主页保存
FPGA相关技术助力高端存储器接口设计
智能锁真的没有机械锁安全吗?防盗性能不足?
声光控制电路图大全(声光控节能灯/延时节电灯/声光控楼梯延迟开关电路)
联电发生跳电事故,民众误以为火灾
隆基再次下调硅片价格 M6报价下调至3.41元/片
鸿蒙ArkUI开发-实现增删Tab页签
锂电池价格构成及价格的影响因素
2025年后智能手机芯片将大量采用3D Chiplet封装
怎么样测试主板上的电容
高温线的作用是什么,它的特性都有哪些
氯霉素快速检测系统设备的原理及用途是什么
新能源补贴政策的逐渐退坡 比亚迪成最大补贴赢家
分享一个STM32菜单框架
浅谈3D打印技术与机器人自动化技术如何打印出球鞋
HGW35CC、EGH15CA、EGH20CA、EGH25SA、EGH30CA型号替换指南
面对网络攻击可以做些什么有效措施
如何提升天线的性能,影响它的因素有哪些
AcrelCloud-3500餐饮油烟监测云平台助力加强环保治理
超声波发生器的种类有哪些?
基于Visual C++程序与C++语言的FPGA可重配置设计方案