在这里插入图片描述

概述

滚动容器是移动应用中处理超出屏幕内容的重要方式,无论是长列表、大图片还是多内容页面,都需要滚动功能来展示完整内容。HarmonyOS ArkUI 提供的 Scroll 组件功能强大,支持水平滚动、垂直滚动和双向滚动等多种模式。本文将从组件基础、滚动方向、事件处理、实际应用等多个维度,深入讲解 Scroll 组件的使用方法。


一、Scroll 组件基础

1.1 组件定义与作用

Scroll 组件用于创建可滚动的内容区域,当内容超出容器尺寸时,用户可以通过滑动查看完整内容。

@Entry
@Component
struct ScrollBasic {
  build() {
    Column() {
      Scroll() {
        Column() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
            Text('项目 ' + index)
              .width('100%')
              .height(60)
              .backgroundColor('#F5F5F5')
              .margin({ bottom: 8 })
          })
        }
      }
      .width('100%')
      .height(300)
    }
  }
}

1.2 构造函数参数

Scroll 的构造函数支持以下参数:

Scroll(options?: {
  scrollable?: ScrollDirection;  // 滚动方向
  scrollBar?: BarState;          // 滚动条状态
  scrollBarColor?: string;       // 滚动条颜色
  scrollBarWidth?: number;       // 滚动条宽度
})

1.3 滚动方向

方向 说明
ScrollDirection.Vertical 垂直滚动
ScrollDirection.Horizontal 水平滚动
ScrollDirection.None 禁止滚动

二、垂直滚动

2.1 基础垂直滚动

垂直滚动是最常用的滚动方式:

@Entry
@Component
struct VerticalScrollDemo {
  build() {
    Column() {
      Scroll() {
        Column() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
            Row() {
              Text('项目 ' + index)
                .fontSize(16)
                .layoutWeight(1)
              Text('内容 ' + index)
                .fontSize(14)
                .fontColor('#999999')
            }
            .width('100%')
            .height(60)
            .padding(16)
            .backgroundColor(index % 2 === 0 ? '#FFFFFF' : '#F8F8F8')
          })
        }
      }
      .width('100%')
      .height(300)
      .scrollBar(BarState.On)
    }
  }
}

2.2 滚动条设置

通过 scrollBar 属性设置滚动条显示状态:

@Entry
@Component
struct ScrollBarDemo {
  build() {
    Column() {
      Text('显示滚动条')
        .fontSize(14)
        .margin({ bottom: 8 })
      
      Scroll() {
        Column() {
          ForEach([1, 2, 3, 4, 5, 6], (index: number) => {
            Text('项目 ' + index)
              .width('100%')
              .height(60)
              .backgroundColor('#F5F5F5')
          })
        }
      }
      .width('100%')
      .height(200)
      .scrollBar(BarState.On)
      .scrollBarColor('#0A59F7')
      .scrollBarWidth(4)
      .margin({ bottom: 16 })
      
      Text('隐藏滚动条')
        .fontSize(14)
        .margin({ bottom: 8 })
      
      Scroll() {
        Column() {
          ForEach([1, 2, 3, 4, 5, 6], (index: number) => {
            Text('项目 ' + index)
              .width('100%')
              .height(60)
              .backgroundColor('#F5F5F5')
          })
        }
      }
      .width('100%')
      .height(200)
      .scrollBar(BarState.Off)
    }
  }
}

三、水平滚动

3.1 基础水平滚动

通过 direction 属性设置水平滚动:

@Entry
@Component
struct HorizontalScrollDemo {
  build() {
    Column() {
      Scroll({ direction: ScrollDirection.Horizontal }) {
        Row() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
            Column() {
              Text('卡片 ' + index)
                .fontSize(14)
            }
            .width(100)
            .height(80)
            .backgroundColor('#E8F0FE')
            .borderRadius(8)
            .alignItems(HorizontalAlign.Center)
            .justifyContent(FlexAlign.Center)
            .margin({ right: 12 })
          })
        }
        .padding(12)
      }
      .width('100%')
      .height(100)
    }
  }
}

3.2 滚动条状态

状态 说明
BarState.On 常驻显示
BarState.Off 隐藏
BarState.Auto 滚动时显示

四、事件处理

4.1 滚动事件监听

通过 onScroll 事件监听滚动位置:

@Entry
@Component
struct ScrollEventDemo {
  @State scrollPosition: number = 0;

  build() {
    Column() {
      Text('滚动位置: ' + Math.round(this.scrollPosition) + 'px')
        .fontSize(14)
        .fontColor('#999999')
        .margin({ bottom: 8 })
      
      Scroll() {
        Column() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
            Text('项目 ' + index)
              .width('100%')
              .height(60)
              .backgroundColor('#F5F5F5')
          })
        }
      }
      .width('100%')
      .height(300)
      .onScroll((xOffset: number, yOffset: number) => {
        this.scrollPosition = yOffset;
      })
    }
  }
}

4.2 滚动到边缘事件

通过 onScrollEdge 事件监听滚动到边缘:

@Entry
@Component
struct ScrollEdgeDemo {
  @State edgeStatus: string = '未到达边缘';

  build() {
    Column() {
      Text('边缘状态: ' + this.edgeStatus)
        .fontSize(14)
        .fontColor('#999999')
        .margin({ bottom: 8 })
      
      Scroll() {
        Column() {
          ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
            Text('项目 ' + index)
              .width('100%')
              .height(60)
              .backgroundColor('#F5F5F5')
          })
        }
      }
      .width('100%')
      .height(300)
      .onScrollEdge((side: Edge) => {
        if (side === Edge.Top) {
          this.edgeStatus = '到达顶部';
        } else if (side === Edge.Bottom) {
          this.edgeStatus = '到达底部';
        }
      })
    }
  }
}

五、实际案例:滚动容器演示

5.1 需求分析

构建一个滚动容器演示页面,包含:

  • 垂直滚动演示
  • 水平滚动演示
  • 滚动方向切换
  • 滚动位置显示

5.2 代码实现

import { router } from '@kit.ArkUI';

@Entry
@Component
struct ScrollDemo {
  @State scrollPosition: number = 0;
  @State scrollDirection: number = 0;

  build() {
    Column() {
      Row() {
        Button('返回')
          .onClick(() => {
            router.back();
          })
        Text('Scroll 组件演示')
          .fontSize(20)
          .fontWeight(FontWeight.Bold)
          .layoutWeight(1)
          .textAlign(TextAlign.Center)
      }
      .width('100%')
      .padding(12)
      .backgroundColor('#F1F3F5')

      Column() {
        Text('垂直滚动演示')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 20, bottom: 12 })
          .width('90%')

        Scroll() {
          Column() {
            ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
              Row() {
                Text('项目 ' + index)
                  .fontSize(16)
                  .fontColor('#333333')
                  .layoutWeight(1)
                Text('内容 ' + index)
                  .fontSize(14)
                  .fontColor('#999999')
              }
              .width('100%')
              .height(60)
              .padding({ left: 16, right: 16 })
              .backgroundColor(index % 2 === 0 ? '#FFFFFF' : '#F8F8F8')
              .alignItems(VerticalAlign.Center)
            })
          }
          .width('100%')
        }
        .width('90%')
        .height(200)
        .backgroundColor('#FFFFFF')
        .borderRadius(8)
        .borderWidth(1)
        .borderColor('#E5E5E5')
        .onScroll((xOffset: number, yOffset: number) => {
          this.scrollPosition = yOffset;
        })

        Text('滚动位置: ' + Math.round(this.scrollPosition) + 'px')
          .fontSize(12)
          .fontColor('#999999')
          .margin({ top: 8 })

        Text('水平滚动演示')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 24, bottom: 12 })
          .width('90%')

        Scroll({ direction: ScrollDirection.Horizontal }) {
          Row() {
            ForEach([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (index: number) => {
              Column() {
                Text('卡片 ' + index)
                  .fontSize(14)
                  .fontColor('#333333')
              }
              .width(100)
              .height(80)
              .backgroundColor('#E8F0FE')
              .borderRadius(8)
              .alignItems(HorizontalAlign.Center)
              .justifyContent(FlexAlign.Center)
              .margin({ right: 12 })
            })
          }
          .padding(12)
        }
        .width('90%')
        .height(100)
        .backgroundColor('#FFFFFF')
        .borderRadius(8)
        .borderWidth(1)
        .borderColor('#E5E5E5')

        Text('滚动方向设置')
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .margin({ top: 24, bottom: 12 })
          .width('90%')

        Column() {
          Row() {
            Button('垂直滚动')
              .layoutWeight(1)
              .height(40)
              .backgroundColor(this.scrollDirection === 0 ? '#0A59F7' : '#F1F3F5')
              .fontColor(this.scrollDirection === 0 ? '#FFFFFF' : '#333333')
              .onClick(() => {
                this.scrollDirection = 0;
              })
            Button('水平滚动')
              .layoutWeight(1)
              .height(40)
              .margin({ left: 8 })
              .backgroundColor(this.scrollDirection === 1 ? '#0A59F7' : '#F1F3F5')
              .fontColor(this.scrollDirection === 1 ? '#FFFFFF' : '#333333')
              .onClick(() => {
                this.scrollDirection = 1;
              })
            Button('双向滚动')
              .layoutWeight(1)
              .height(40)
              .margin({ left: 8 })
              .backgroundColor(this.scrollDirection === 2 ? '#0A59F7' : '#F1F3F5')
              .fontColor(this.scrollDirection === 2 ? '#FFFFFF' : '#333333')
              .onClick(() => {
                this.scrollDirection = 2;
              })
          }
        }
        .width('90%')
        .backgroundColor('#FFFFFF')
        .padding(16)
        .borderRadius(8)

        Text('提示:Scroll 组件支持水平、垂直和双向滚动,通过 direction 属性设置')
          .fontSize(12)
          .fontColor('#999999')
          .margin({ top: 24 })
          .width('90%')
          .textAlign(TextAlign.Center)
      }
      .width('100%')
      .layoutWeight(1)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}

六、Scroll 与 List 对比

6.1 功能对比

特性 Scroll List
内容类型 任意内容 列表数据
滚动方向 水平/垂直 垂直为主
懒加载 不支持 支持
适用场景 通用滚动 大数据列表

6.2 使用场景建议

场景 推荐组件
长列表数据 List
表单页面滚动 Scroll
横向卡片滚动 Scroll
大图片查看 Scroll

七、最佳实践

7.1 性能优化

建议 说明
控制内容大小 避免过多嵌套
合理设置高度 确保滚动区域正确
使用滚动条 提示用户可滚动

7.2 常见问题

问题 解决方案
无法滚动 检查内容是否超出容器
滚动条不显示 设置 scrollBar 属性
滚动方向错误 检查 direction 设置

八、总结

Scroll 组件是处理超出屏幕内容的重要组件,掌握其使用方法对于构建复杂页面至关重要。

核心要点

  1. 使用 direction 设置滚动方向
  2. 使用 scrollBar 设置滚动条显示
  3. 使用 onScroll 监听滚动位置
  4. 垂直滚动适合长内容页面
  5. 水平滚动适合卡片展示

希望本文能帮助你更好地理解和使用 Scroll 组件,构建出优秀的 HarmonyOS 应用。


参考资料

更多推荐