HarmonyOS鸿蒙Next中如何实现带下标滚动的金刚区

HarmonyOS鸿蒙Next中如何实现带下标滚动的金刚区 滚动下标跟随金刚区滚动同步,进度一致。

3 回复

实现细节:

1、使用横向的List实现金刚区

2、使用两个Row内嵌实现滚动下标

3、在List的onDidScroll回调中计算滚动进度

4、通过修改下标内部Row的offset来达到同步滚动的效果

预览效果:

preview

完整demo代码:

/**
 * @fileName : MenuView.ets
 * @author : @cxy
 * @date : 2025/12/19
 * @description : 金刚区
 */

export class MenuViewItem {
  name: string = ''
  url: ResourceStr = ''
}

@Component
export struct MenuView {
  @State offsetX: number = 0
  @State menuWidth: number = 0
  @State menus: MenuViewItem[] = []
  private columnCount: number = 5
  private scroller: Scroller = new Scroller()

  onDidBuild(): void {
    const list: MenuViewItem[] = []
    for (let index = 0; index < 8; index++) {
      list.push({
        name: 'name' + index,
        url: $r('app.media.startIcon')
      })
    }
    this.menus = list
  }

  build() {
    Column({ space: 8 }) {
      List({ scroller: this.scroller, space: 5 }) {
        ForEach(this.menus, (item: MenuViewItem) => {
          ListItem() {
            Column({ space: 5 }) {
              Image(item.url)
                .width(36)
                .height(36)
                .objectFit(ImageFit.Contain)

              Text(item.name)
                .fontColor('#666')
                .fontSize(13)
                .maxLines(1)
                .textOverflow({ overflow: TextOverflow.Ellipsis })
                .textAlign(TextAlign.Center)
            }
            .constraintSize({
              minWidth: (this.menuWidth - this.columnCount * (this.columnCount - 1)) / this.columnCount
            })
            .alignItems(HorizontalAlign.Center)
          }
          .onClick(() => {

          })

        }, (item: MenuViewItem) => item.name)
      }
      .height(60)
      .width('100%')
      .listDirection(Axis.Horizontal)
      .edgeEffect(EdgeEffect.Spring)
      .scrollBar(BarState.Off)
      .onDidScroll((scrollOffset: number, scrollState: ScrollState) => {
        const count = this.columnCount
        if (this.menus.length > count) {
          const offsetX = this.scroller.currentOffset().xOffset
          const contentWidth = this.menus.length * (this.menuWidth / count)
          let precent = offsetX / (contentWidth - this.menuWidth)
          precent = Math.min(1, precent)
          precent = Math.max(0, precent)
          this.offsetX = (30 - 14 - 2) * precent
        }
      })

      if (this.menus.length > this.columnCount) {
        Row() {
          Row()
            .height(4)
            .borderRadius('50%')
            .width(14)
            .backgroundColor('#ff005eff')
            .offset({ x: this.offsetX })
        }
        .backgroundColor('#DBEDFF')
        .borderRadius('50%')
        .width(30)
        .padding(1)
      }
    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
    .width('100%')
    .onAreaChange((oldValue: Area, newValue: Area) => {
      this.menuWidth = newValue.width as number
    })
    .margin({ top: 20 })
  }
}

更多关于HarmonyOS鸿蒙Next中如何实现带下标滚动的金刚区的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中实现带下标滚动的金刚区,可使用Swiper组件嵌套Tabs组件实现。Swiper负责横向滚动展示图标区域,Tabs的TabBar作为下标指示器。通过Swiper的onChange事件与Tabs的onChange事件联动,保持两者索引同步。主要涉及ArkUI的声明式开发,使用Swiper、Tabs、Flex等布局组件组合完成。

在HarmonyOS Next中实现带下标滚动的金刚区(通常指水平滚动的图标导航区),核心是结合Scroll组件与下标指示器,并保持两者状态同步。以下是关键实现步骤和代码思路:

1. 布局结构

使用Scroll组件作为水平滚动容器,内部用Row布局金刚区图标。下标指示器通常用Flex布局的一排圆点,与Scroll同级。

2. 关键实现

  • 滚动监听:通过ScrollonScroll事件获取滚动偏移量(scrollOffset)。
  • 下标计算:根据滚动偏移量和每个金刚项宽度,计算当前激活的下标索引。
  • 状态同步:使用@State装饰器管理激活下标,触发UI更新。

示例代码框架

import { Scroll, Row, Flex, Circle, Text } from '@kit.ArkUI';

@Entry
@Component
struct DiamondArea {
  // 金刚区数据
  private items: Array<string> = ['Item1', 'Item2', 'Item3', 'Item4', 'Item5'];
  // 当前激活下标
  @State activeIndex: number = 0;
  // 每个金刚项宽度(需根据实际样式调整)
  private itemWidth: number = 100;

  build() {
    Column() {
      // 1. 金刚区滚动部分
      Scroll() {
        Row() {
          ForEach(this.items, (item: string, index: number) => {
            Column() {
              // 图标组件(示例用Circle代替)
              Circle({ width: 60, height: 60 })
                .fill('#007DFF')
              Text(item)
                .fontSize(14)
            }
            .width(this.itemWidth)
            .onClick(() => {
              // 点击跳转到对应位置
              this.activeIndex = index;
            })
          })
        }
        .height(120)
      }
      .scrollable(ScrollDirection.Horizontal)
      .onScroll((scrollOffset: number) => {
        // 根据滚动位置计算激活下标
        this.activeIndex = Math.round(scrollOffset / this.itemWidth);
      })

      // 2. 下标指示器
      Flex({ justifyContent: FlexAlign.Center }) {
        ForEach(this.items, (_: string, index: number) => {
          Circle({
            width: this.activeIndex === index ? 12 : 8,
            height: this.activeIndex === index ? 12 : 8
          })
            .fill(this.activeIndex === index ? '#007DFF' : '#E5E5E5')
            .margin(4)
        })
      }
      .margin({ top: 10 })
    }
  }
}

3. 优化点

  • 滚动动画:可使用scrollTo方法实现点击下标时平滑滚动到对应位置。
  • 自适应宽度:通过GeometryReader或组件回调动态获取实际项宽度,提升精度。
  • 性能:大量数据时建议使用LazyForEach优化滚动列表。

注意事项

  • 确保itemWidth与实际渲染宽度一致,避免下标计算偏差。
  • 滚动事件频率较高,避免在onScroll中执行复杂逻辑。

以上方案通过响应式状态绑定,实现了金刚区滚动与下标指示器的实时同步。

回到顶部