HarmonyOS 鸿蒙Next 自定义 Tabs

发布于 1周前 作者 h691938207 来自 鸿蒙OS

HarmonyOS 鸿蒙Next 自定义 Tabs

自定义 Tabs

ArkUI 默认提供的 tabs 不满足我们的设计需求

自定义导航条跟随效果

实现这个导航条跟随效果的思路

  1. 获取每个点击模块的宽度
  2. 获取每个点击模块距离父元素的偏移量
  3. 计算导航条的位置
  4. 通过显式动画更新状态

如何获取节点的宽高位置信息

  1. 组件内可以通过 this.getUIContext().getComponentUtils().getRectangleById('组件id')
aboutToApper() {
    const info = this.getUIContext().getComponentUtils().getRectangleById('组件id')
}
  1. 通过 import { componentUtils } from '@kit.ArkUI'
aboutToApper() {
    const info = componentUtils.getRectangleById('组件id')
}

区别就是导包不导包的区别

什么环节获取信息

从UI效果场景分析

  1. 初始化的时候定义导航条初始位置
  2. 点击的时候定义导航条位置

第一点就是在组件挂载完后获取 也有两种方式

  1. 组件内通过 this.getUIContext().getUIInspector().createComponentObserver('组件Id') 创建一个UI审查对象
@Component
struct Index {
    listener: inspector.ComponentObserver = this.getUIContext().getUIInspector().createComponentObserver('第一个tab的id')
}
  1. 导入 import { inspector } from '@kit.ArkUI' 获取
@Component
struct Index {
    listener: inspector.ComponentObserver = inspector.createComponentObserver('第一个tab的id')
}
  1. 监听组件布局完成
aboutToAppear(): void {
   this.listener.on('draw', this.initLeft)
}

aboutToDisappear(): void {
   this.listener.off('draw', this.initLeft)
   this.isInit = false
}

initLeft = () => {
  // 设置位置逻辑
}

计算居中的算法

(选中元素宽度 - 导航条宽度) / 2 + 选中元素的距离父元素的偏移量

具体实现

import { componentUtils, inspector } from '@kit.ArkUI'

export interface IJTabsItem {
    name: string
    title: string
}

const ACTIVE_KEY = 'activeId_'

@Component
export struct JTabs {
    @Prop tabs: IJTabsItem[] = []
    @Prop initId: string
    @State activeId: string = `${ACTIVE_KEY}0`
    @State scrollLeft: number = 0
    listener: inspector.ComponentObserver = inspector.createComponentObserver(this.activeId)
    isInit: boolean = false
    click: (item: IJTabsItem) => void = () => {}

    aboutToAppear(): void {
        this.listener.on('draw', this.initLeft)
    }

    aboutToDisappear(): void {
        this.listener.off('draw', this.initLeft)
        this.isInit = false
    }

    initLeft = () => {
        if (this.isInit) {
            return
        }
        this.isInit = true
        this.activeId = this.initId
        this.setScrollLeft()
    }

    // 计算滚动距离
    setScrollLeft() {
        const r = componentUtils.getRectangleById(this.activeId)
        const width = px2vp(r.size.width)
        const offsetX = px2vp(r.localOffset.x)
        const half = (width - 20) / 2
        animateTo({
            duration: 100,
            curve: Curve.Linear
        }, () => {
            this.scrollLeft = offsetX + half
        })
    }

    // tabs 大于5个切换到滚动
    isScroll() {
        return this.tabs.length > 5
    }

    @Builder
    renderTabs() {
        Row() {
            ForEach(this.tabs, (item: IJTabsItem, index: number) => {
                Text(item.title)
                    .height('100%')
                    .id(`${ACTIVE_KEY}${index}`)
                    .onClick(() => {
                        const currentActiveId = `${ACTIVE_KEY}${index}`
                        this.activeId = currentActiveId
                        console.log('xxxxxxxxx', this.activeId)
                        this.setScrollLeft()
                        this.click && this.click(item)
                    })
                    .fontWeight(this.activeId === `${ACTIVE_KEY}${index}` ? 600 : 400)
            })
            Text()
                .width(24)
                .height(2)
                .backgroundColor('#191919')
                .borderRadius(100000)
                .position({
                    x: 0,
                    y: '100%'
                })
                .translate({
                    x: this.scrollLeft,
                    y: '-100%'
                })
        }
        .height(60)
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .backgroundColor('#fff')
    }

    build() {
        if (this.isScroll()) {
            Scroll() {
                Row() {
                  // 这里是切换到 Scroll 场景的导航条
                  // 逻辑一样
                }
            }
        }
        else {
            Row() {
                this.renderTabs()
            }
            .width('100%')
        }
    }
}

使用

import { JTabs, IJTabsItem } from 'xxxx';

@Entry
@Component
struct OrderLIstPage {
    @State tabs: IJTabsItem[] = [
        {
            title: '全部',
            name: 'activeId_0'
        },
        {
            title: '待付款',
            name: 'activeId_1'
        },
        {
            title: '待发货',
            name: 'activeId_2'
        },
        {
            title: '待收货',
            name: 'activeId_3'
        },
        {
            title: '待评价',
            name: 'activeId_4'
        }
    ]

    build() {
        Column() {
            Row() {
                JTabs({
                    tabs: this.tabs,
                    click: () => {}
                })
            }
            .width('100%')
            .padding({
                left: 16,
                right: 16
            })
            .backgroundColor('#fff')
        }
        .height('100%')
        .width('100%')
        .backgroundColor('#f5f5f5')
    }
}

更多关于HarmonyOS 鸿蒙Next 自定义 Tabs的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

HarmonyOS 鸿蒙Next 中自定义 Tabs 可以通过使用 TabListTab 组件来实现。TabList 是一个容器组件,用于承载多个 Tab 组件,每个 Tab 代表一个标签页。开发者可以通过设置 TabListTab 的属性来自定义标签页的外观和行为。

在鸿蒙Next中,TabList 提供了多种布局方式,如水平布局和垂直布局,开发者可以通过 orientation 属性来设置。Tab 组件支持设置图标、文本以及选中状态下的样式。开发者可以通过 icon 属性为标签页添加图标,通过 text 属性设置标签页的文本内容。

此外,TabList 还支持通过 onChange 事件监听标签页的切换,开发者可以在事件回调中处理标签页切换时的逻辑。通过 selectedIndex 属性,可以设置默认选中的标签页。

自定义 Tabs 的样式可以通过 style 属性进行设置,开发者可以自定义标签页的背景色、文字颜色、边框等样式。鸿蒙Next 还提供了 TabListController 类,用于动态控制 TabList 的行为,如添加、删除标签页,以及设置选中状态等。

总之,鸿蒙Next 提供了丰富的 API 和组件,开发者可以灵活地自定义 Tabs 的外观和行为,以满足不同的应用场景需求。

更多关于HarmonyOS 鸿蒙Next 自定义 Tabs的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS(鸿蒙)Next中,自定义Tabs可以通过TabListTab组件实现。首先,使用TabList作为容器,然后在其中添加多个Tab组件,每个Tab代表一个标签页。你可以通过Tabtext属性设置标签名称,并通过onClick事件处理点击逻辑。此外,可以通过selected属性控制当前选中的标签页。为了进一步自定义样式,可以使用style属性或CSS类来调整外观。通过这种方式,你可以灵活地创建符合应用需求的Tabs组件。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!