70.HarmonyOS NEXT PicturePreview组件深度剖析:从架构设计到核心代码实现

2025-03-15 23:46:17
140次阅读
0个评论

温馨提示:本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦!

HarmonyOS NEXT PicturePreview组件深度剖析:从架构设计到核心代码实现

70_1.png

一、组件整体架构

1. 组件功能

  • 实现图片预览功能,支持水平和垂直滑动
  • 支持懒加载和手势交互
  • 可自定义背景色和切换动画
  • 适配不同屏幕尺寸

2. 技术栈

HarmonyOS ETS + 自定义手势 + 矩阵变换 + 懒加载

二、核心代码解析

1. 组件参数

@Prop listDirection: Axis = Axis.Vertical // 滑动方向(默认垂直)
@Link @Watch('getListMaxLength') imageList: string[] // 双向绑定的图片数据源
  • **@Prop**:父组件传入的不可变参数
  • **@Link**:实现父子组件双向数据绑定
  • **@Watch**:当imageList变化时自动触发getListMaxLength

2. 状态管理

@State listBGColor: Color = Color.White // 背景色状态
@State lazyImageList: CommonLazyDataSourceModel<string> // 懒加载数据源
  • **@State**:组件内部状态,变化触发UI更新
  • CommonLazyDataSourceModel:优化内存的懒加载模型

3. 控制相关

private listScroll: ListScroller = new ListScroller() // 列表滚动控制器
private listAnimationDuration: number = 500 // 滑动动画时长
  • ListScroller:精确控制列表滚动位置
  • 动画时长控制滑动流畅度

三、关键方法详解

1. 数据初始化

aboutToAppear(): void {
    this.getListMaxLength()
}

getListMaxLength() {
    this.listMaxLength = this.imageList.length
    this.lazyImageList.clearAndPushAll(this.imageList)
}
  • 生命周期:组件创建时触发
  • 数据转换:将普通数组转为懒加载数据源

2. 滚动控制逻辑

setListOffset(offset: number, animationDuration: number = 0) {
    const WIN_SIZE = windowSizeManager.get()
    // 计算主轴尺寸
    let principalAxisSize = this.listDirection === Axis.Horizontal 
        ? WIN_SIZE.width 
        : WIN_SIZE.height
    // 计算偏移量
    let principalAxisOffset = principalAxisSize * this.listIndex + this.listSpace * this.listIndex
    // 执行滚动
    this.listScroll.scrollTo({
        yOffset: this.listDirection === Axis.Horizontal ? 0 : principalAxisOffset,
        xOffset: this.listDirection === Axis.Horizontal ? principalAxisOffset : 0,
        animation: { duration: animationDuration }
    })
}
  • 窗口适配:通过windowSizeManager获取屏幕尺寸
  • 方向判断:根据滑动方向计算不同轴向的偏移量
  • 平滑滚动:支持自定义动画时长

3. 页面跳转

setListToIndex(index: number) {
    // 边界检查
    let nIndex = Math.max(0, Math.min(index, this.listMaxLength - 1))
    // 计算目标位置
    const principalAxisSize = this.listDirection === Axis.Horizontal 
        ? windowSizeManager.get().width 
        : windowSizeManager.get().height
    const calculatedOffset = nIndex * (principalAxisSize + this.listSpace)
    // 执行跳转
    this.listScroll.scrollTo({
        xOffset: this.listDirection === Axis.Horizontal ? calculatedOffset : 0,
        yOffset: this.listDirection === Axis.Vertical ? calculatedOffset : 0,
        animation: { duration: this.listAnimationDuration }
    })
}
  • 安全处理:限制index在有效范围内
  • 精确计算:考虑列表间距(listSpace)的影响
  • 动画控制:使用预设动画时长保证体验一致

四、UI构建逻辑

1. 列表构建

List({ 
    scroller: this.listScroll, 
    space: this.listSpace 
}) {
    LazyForEach(this.lazyImageList, (imageUrl: string, index: number) => {
        ListItem() {
            PicturePreviewImage({
                imageUrl: imageUrl,
                // 传递参数...
            })
        }
        .width("100%")
    })
}
  • LazyForEach:优化性能的懒加载循环
  • ListItem:每个图片项的容器
  • width("100%"):撑满父容器宽度

2. 列表配置

.enableScrollInteraction(false) // 禁用默认滑动
.scrollSnapAlign(ScrollSnapAlign.START) // 对齐方式
.cachedCount(1) // 缓存数量
.listDirection(this.listDirection) // 滑动方向
.scrollBar(BarState.Off) // 隐藏滚动条
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  • 关键配置
    • enableScrollInteraction(false):避免与自定义手势冲突
    • cachedCount(1):平衡内存与性能
    • expandSafeArea:适配系统安全区域

五、特殊处理说明

1. 透明边框处理

.borderWidth(1)
.borderColor(Color.Transparent)
  • 问题背景:修复鸿蒙系统Y轴定位异常
  • 解决方案:添加透明边框占位
  • 注意事项:不可移除,等待系统修复

2. 背景色切换

.onClick(() => {
    this.listBGColor = this.listBGColor === Color.White 
        ? Color.Black 
        : Color.White
})
  • 交互功能:点击列表切换背景色
  • 实现原理:通过@State触发重新渲染

六、组件使用示例

1. 父组件调用

@Entry
@Component
struct Example {
    @State images: string[] = [
        "common/image1.jpg",
        "common/image2.jpg",
        "common/image3.jpg"
    ]

    build() {
        Column() {
            PicturePreview({
                imageList: $rawfile(this.images),
                listDirection: Axis.Horizontal
            })
        }
    }
}

2. 参数说明

参数名 类型 必填 说明
imageList string[] 图片路径数组
listDirection Axis 滑动方向(默认垂直)

七、性能优化点

  1. 懒加载机制

    • 使用LazyForEach按需创建列表项
    • cachedCount(1)减少内存占用
  2. 渲染优化

    • 固定尺寸计算避免重复布局
    • 禁用不必要的滚动条
  3. 手势优化

    • 自定义手势控制替代系统滚动
    • 精准的动画时长控制
收藏00

登录 后评论。没有帐号? 注册 一个。