鸿蒙原生 ArkTS 布局精讲:List 自定义滑动器(ScrollBar)从入门到实战


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、引言

在移动端应用开发中,列表(List)是最常见、最核心的交互容器之一。而滚动条(ScrollBar)作为列表的"导航标尺",其视觉风格和交互体验直接影响用户对应用品质的感知。

鸿蒙 ArkTS 在 API 24 中提供了极其灵活的滚动条定制能力——开发者不再局限于系统默认的"灰条",而是可以通过 .scrollBar().scrollBarColor().scrollBarWidth() 三个链式 API,完全掌控滚动条的显示逻辑与外观风格

本文将从零开始,带你一步步构建一个支持实时切换滚动条模式、颜色、宽度的交互式演示页面,深刻理解鸿蒙 ArkTS 布局系统的设计哲学。


二、ScrollBar 核心 API 全景

2.1 三大核心方法

API 方法 参数类型 作用 默认值
.scrollBar(state) BarState 枚举 控制滚动条显示/隐藏策略 BarState.Auto
.scrollBarColor(color) ResourceColor 自定义滚动条轨道颜色 系统半透明灰
.scrollBarWidth(value) number 自定义滚动条宽度(vp) 系统默认值(约 4vp)

2.2 BarState 三态详解

BarState 是控制滚动条"什么时候出现"的关键枚举,包含三个值:

BarState.Auto  —— 内容可滚动时显示,静止时自动隐藏(默认值)
BarState.On    —— 始终显示滚动条,不随滚动状态改变
BarState.Off   —— 始终隐藏滚动条,完全交由开发者自定义

💡 设计洞察BarState.Auto 适用于绝大多数通用场景;BarState.On 适合需要明确提示"此处可滚动"的信息型页面;BarState.Off 通常用于完全自定义滚动指示器的场景。


三、项目搭建与前置准备

3.1 创建项目

在 DevEco Studio 中创建 HarmonyOS 工程,选择 Empty Ability 模板,语言选择 ArkTS。核心配置如下:

// build-profile.json5
{
  "app": {
    "products": [{
      "name": "default",
      "targetSdkVersion": "6.1.0(23)",
      "compatibleSdkVersion": "6.1.0(23)",
      "runtimeOS": "HarmonyOS"
    }]
  }
}

3.2 页面路由注册

main_pages.json 中注册新页面:

{
  "src": ["pages/Index", "pages/ScrollBarDemo"]
}

⚠️ 注意:所有页面必须显式注册到路由表中才能通过 router.pushUrl() 跳转。

3.3 首页导航入口

Index.ets 中添加导航卡片,使用 router.pushUrl 跳转到演示页面:

Column() {
  Row({ space: 16 }) {
    Text('🎨').fontSize(36)
    Column({ space: 6 }) {
      Text('List 自定义滑动器').fontSize(18)
      Text('滚动条显示/隐藏及颜色、宽度自定义').fontSize(13)
    }
  }
  .padding(16)
}
.borderRadius(12)
.onClick(() => {
  router.pushUrl({ url: 'pages/ScrollBarDemo' });
})

四、核心实现:ScrollBarDemo 页面

这是整个教程的核心。我们构建一个带控制面板的实时预览页面,让读者可以直观感受每个 API 参数的视觉影响。

4.1 整体结构

页面分为上下两个区域:上方的控制面板(模式/颜色/宽度调节器)和下方的列表预览区(50 条卡片 + 自定义滚动条)。三个 @State 变量驱动控制面板与列表区的联动,任何调节都会触发列表滚动条的实时更新。

4.2 状态变量设计

@State selectedModeIndex: number = 0;  // 滚动条模式索引
@State barWidth: number = 6;            // 滚动条宽度(vp)
@State barColor: string = '#664096FF';  // 滚动条颜色

🎯 为何用 @State?
鸿蒙 ArkTS 中,@State 变量一旦被修改,框架自动触发组件重新渲染。控制面板修改这些变量,列表区自动响应——数据驱动 UI 正是声明式开发的精髓。

4.3 数据层

50 条示例数据确保列表足够长以触发滚动;6 种颜色预设覆盖主流色调:

private readonly colorPresets: ScrollBarColorPreset[] = [
  { label: '蓝色(默认)', color: '#664096FF' },
  { label: '橙色', color: '#66FF7500' },
  { label: '绿色', color: '#66A6D500' },
  { label: '红色', color: '#66F53130' },
  { label: '紫色', color: '#66B620D2' },
  { label: '黑色', color: '#66000000' },
];

private readonly itemSource: string[] = new Array<string>(50).fill('').map(
  (_: string, i: number): string => `${i + 1} 项 — 鸿蒙 ArkTS 自定义滚动条演示`
);

private readonly modeList: BarStateItem[] = [
  { label: 'Auto(自适应)', value: BarState.Auto },
  { label: 'On(始终显示)',  value: BarState.On },
  { label: 'Off(始终隐藏)', value: BarState.Off },
];

4.4 核心布局:List + ScrollBar

这是整个页面最关键的代码段——仅三行链式调用,完成滚动条全面定制

List({ space: 8, initialIndex: 0 }) {
  ForEach(this.itemSource, (item: string, index: number): void => {
    ListItem() {
      this.buildListItem(`${index + 1}`, item)
    }
  }, (item: string, index: number): string => `${index}`)
}
.width('100%')
.layoutWeight(1)
.borderRadius(12)
.padding({ left: 12, right: 12, top: 8, bottom: 8 })
.backgroundColor('#F5F5F5')

// ———— 核心 API:三行定制滚动条 ————
.scrollBar(this.currentMode)       // BarState 控制显示策略
.scrollBarColor(this.barColor)     // 任意颜色 + 透明度
.scrollBarWidth(this.barWidth)     // 2~20 vp 自由调节

.edgeEffect(EdgeEffect.Spring)
.sticky(StickyStyle.Header)

🔑 关键理解:这三个 API 均为 List(及 Scroll)组件的内置方法,通过链式调用直接附加滚动条行为。不需要单独的 ScrollBar 组件子节点——这是 API 24 推荐的标准做法。

4.5 控制面板 Builder

控制面板使用 @Builder 装饰器封装,包含三个调节区:

模式选择区——三个按钮对应 BarState 的三个枚举值,点击即切换 selectedModeIndex

Row({ space: 8 }) {
  ForEach(this.modeList, (item: BarStateItem, idx: number): void => {
    Button(item.label)
      .fontColor(this.selectedModeIndex === idx ? '#FFF' : '#666')
      .backgroundColor(this.selectedModeIndex === idx ? '#007DFF' : '#F0F0F0')
      .onClick((): void => { this.selectedModeIndex = idx; })
  })
}

颜色选择区——6 个圆形色块,选中态使用白色边框加阴影高亮:

Row({ space: 8 }) {
  ForEach(this.colorPresets, (preset: ScrollBarColorPreset): void => {
    Column() {
      Row()
        .width(28).height(28).borderRadius(14)
        .backgroundColor(preset.color)
        .border({ width: this.barColor === preset.color ? 3 : 0, color: '#FFF' })
    }
    .borderRadius(18)
    .border({ width: this.barColor === preset.color ? 2 : 1,
              color: this.barColor === preset.color ? '#007DFF' : '#D0D0D0' })
    .onClick((): void => { this.barColor = preset.color; })
  })
}

宽度调节区——Slider 滑块从 2 vp 到 20 vp 连续调节,实时显示数值:

Row({ space: 12 }) {
  Slider({ value: this.barWidth, min: 2, max: 20, step: 1,
           style: SliderStyle.OutSet })
    .layoutWeight(1).showSteps(true).showTips(true)
    .onChange((val: number): void => { this.barWidth = val; })
  Text(`${this.barWidth} vp`).fontSize(14)
    .fontWeight(FontWeight.Bold).fontColor('#007DFF')
}

4.6 列表项 Builder

每个列表项采用卡片式设计——左侧圆形序号、中间内容文字、右侧箭头:

@Builder
buildListItem(seq: string, text: string) {
  Row({ space: 12 }) {
    Text(seq).fontSize(16).fontWeight(FontWeight.Bold)
      .fontColor('#FFF').textAlign(TextAlign.Center)
      .width(36).height(36).borderRadius(18)
      .backgroundColor('#007DFF')
    Text(text).fontSize(15).fontColor('#333')
      .layoutWeight(1)
    Text('›').fontSize(20).fontColor('#CCC')
  }
  .width('100%').height(56)
  .padding({ left: 12, right: 12 })
  .backgroundColor('#FFF').borderRadius(10)
  .shadow({ radius: 2, color: '#10000000', offsetY: 1 })
}

五、关于 import 的重要提醒

这是初学者最容易踩坑的地方,务必注意。

5.1 哪些类型无需 import?

在鸿蒙 ArkTS(API 24)中,以下类型是内置全局类型不需要 import:

类型 是否需 import
BarState ❌ 不需要
FontWeightTextAlign ❌ 不需要
SliderStyle ❌ 不需要
EdgeEffectFlexAlign ❌ 不需要
@Entry@Component@State@Builder ❌ 不需要

5.2 哪些类型需要 import?

只有真正来自 @kit.ArkUI 模块的类/函数才需要导入,例如:

import { router } from '@kit.ArkUI';       // 路由API
import { curves } from '@kit.ArkUI';        // 动画曲线
import { ColorMetrics } from '@kit.ArkUI';  // 颜色度量

5.3 常见误区

初学者最容易犯的错误是:试图从 @kit.ArkUI 导入所有名称。这是不必要的——框架级别的枚举和装饰器直接注入全局命名空间,避免在每个文件中重复导入。

📌 原则:如果报错 Cannot find name 'XXX',先检查它是否属于内置全局类型;如果是,直接使用即可。


六、运行效果预览

6.1 默认状态

列表加载 50 条卡片数据,右侧出现半透明蓝色滚动条,模式为 Auto,列表静止时滚动条淡出,滑动时出现,宽度 6vp。

6.2 交互操作一览

操作 预期效果
点击「On / 始终显示」 滚动条立即变为常驻显示
点击「Off / 始终隐藏」 滚动条立即消失,列表仍可滑动
点击橙色色块 滚动条变色为橙色
拖动 Slider 至 12 vp 滚动条宽度明显变粗

6.3 组合效果示例

  • On + 绿色 + 8vp:始终显示、绿色、8vp 宽的滚动条,适合品牌色统一的应用
  • Auto + 紫色半透明 + 4vp:细窄柔和的滚动条,适合阅读类应用

七、性能优化建议

7.1 长列表用 LazyForEach

当列表数据量极大(1000+ 条)时,使用 LazyForEach 替代 ForEach 可显著降低内存占用:

private dataSource: MyDataSource = new MyDataSource(this.itemSource);
LazyForEach(this.dataSource, (item: string): void => {
  ListItem() { /* ... */ }
}, (item: string): string => item);

7.2 合理选择 BarState

  • 内容少(3~5 项):建议 BarState.Off——滚动条此时无意义
  • 内容多(20+ 项):BarState.Auto 最符合用户预期
  • 需要提示"此处可滑动":使用 BarState.On

八、延伸思考:ScrollBar 独立组件

除了在 List 上直接使用链式 API,鸿蒙 API 24 还提供了独立的 ScrollBar 组件,可以绑定到任意 Scroller 上实现更灵活的布局:

Scroll(this.scroller) {
  // 内容...
}
.scrollBar(BarState.Off)  // 隐藏默认滚动条

// 独立悬浮滚动条
ScrollBar({ scroller: this.scroller, state: BarState.Auto })
  .scrollBarColor('#664096FF')
  .scrollBarWidth(8)
  .position({ right: 0 })

这种方式的优势在于:滚动条可以脱离列表边界,自由定位,适用于有特殊布局要求的场景。API 24 还增加了 ArcScrollBar 组件,支持弧形滚动条样式。


九、常见问题排查

Q1:报错 Cannot find name 'BarState'

原因:尝试 import 了本不需要的内置全局类型。
解决:删除针对 BarStateFontWeight 等类型的 import 语句。

Q2:报错 Module ... has no exported member 'XXX'

原因:从 @kit.ArkUI 导入了一个全局内置类型,该类型不应该被 import。
解决:确认该类型是否为内置全局类型(见第五章表格)。

Q3:滚动条没有显示

可能原因 1:列表内容高度未超出容器高度。
解决:确保有足够子节点(如 50 条)且高度超出容器显示区。

可能原因 2:误将 BarState 设置为 Off
解决:切换为 AutoOn 模式验证。

Q4:.scrollBarWidth() 设置无效

原因:targetSdkVersion 低于 API 24。
解决:确认 build-profile.json5 中 targetSdkVersion 为 6.1.0 或更高。


十、总结

通过本文的完整实战,我们系统性地掌握了鸿蒙 ArkTS 中 List 自定义滑动器的全部核心知识点:

  1. .scrollBar(BarState)——控制滚动条显示策略的入口
  2. .scrollBarColor(ResourceColor)——任意自定义颜色,支持透明度
  3. .scrollBarWidth(number)——从 2vp 到 20vp 的宽度自由调节

这三个 API 的组合使用可以覆盖绝大多数定制场景。更重要的是,通过控制面板的实时交互,我们直观地验证了鸿蒙声明式 UI 的核心哲学:数据驱动视图,@State 一变,UI 自动更新

下一步实践建议

  • 将自定义滚动条应用到真实项目中的消息列表、商品列表、设置页
  • 结合 LazyForEach 优化千级数据量的列表性能
  • 探索 ScrollBar 独立组件和 ArcScrollBar 弧形滚动条
  • 使用 .edgeEffect(EdgeEffect.Spring) 等辅助 API 优化滚动交互手感

本文为鸿蒙 ArkTS 布局系列教程之一,欢迎在实践中反馈问题与建议。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐