95.HarmonyOS NEXT 图片约束处理教程:深入理解Constrain

2025-03-16 23:35:45
143次阅读
0个评论

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

95_1.png

HarmonyOS NEXT 图片约束处理教程:深入理解Constrain

1. 图片约束基础

1.1 核心概念

概念 说明 应用场景
图片适配类型 定义图片如何适应容器 图片展示方式
偏移约束 限制图片移动范围 拖拽和缩放
边界检测 判断是否超出显示范围 图片浏览

1.2 图片适配类型定义

export enum ImageFitType {
    TYPE_WIDTH = 'width',
    TYPE_HEIGHT = 'height',
    TYPE_DEFAULT = 'default'
}

2. 偏移计算实现

2.1 最大偏移量计算

export function getMaxAllowedOffset(
  winSize: number,
  imageSize: number,
  scale: number
) {
    const maxNum = Math.max(imageSize * scale, winSize);
    const minNum = Math.min(imageSize * scale, winSize);
    return (maxNum - minNum) / 2;
}

2.2 偏移约束实现

function constrainOffset(
  offset: number,
  winSize: number,
  imageSize: number,
  scale: number
): number {
    let maxAllowedOffset = getMaxAllowedOffset(winSize, imageSize, scale);
    return Math.min(Math.max(offset, -maxAllowedOffset), maxAllowedOffset);
}

3. 图片切换判断

3.1 切换条件判断

function isToggle(
  offset: number,
  winSize: number,
  imageSize: number,
  scale: number,
  TogglePercent: number
): boolean {
    let maxAllowedOffset = getMaxAllowedOffset(winSize, imageSize, scale);
    const deviation = Math.abs(offset) - maxAllowedOffset;
    const switchThreshold = winSize * TogglePercent;

    return deviation > switchThreshold;
}

3.2 参数说明

参数 说明 用途
offset 当前偏移量 记录当前位置
winSize 窗口大小 确定显示范围
imageSize 图片大小 计算实际尺寸
scale 缩放比例 处理缩放效果
TogglePercent 切换阈值 控制切换灵敏度

4. 图片尺寸处理

4.1 尺寸获取函数

export function getImgSize(
  imageSize: image.Size,
  rotate: number,
  dimensionWH: ImageFitType.TYPE_WIDTH | ImageFitType.TYPE_HEIGHT
): number {
    const isStandardRotation = [90, 270].includes(Math.abs(rotate % 360));
    const Key = isStandardRotation ? 
      (dimensionWH == ImageFitType.TYPE_WIDTH ? 
        ImageFitType.TYPE_HEIGHT : 
        ImageFitType.TYPE_WIDTH) :
      dimensionWH;
    return imageSize[Key];
}

4.2 旋转处理

  1. 标准旋转判断
const isStandardRotation = [90, 270].includes(Math.abs(rotate % 360));
  1. 维度切换
const Key = isStandardRotation ? 
  (dimensionWH == ImageFitType.TYPE_WIDTH ? 
    ImageFitType.TYPE_HEIGHT : 
    ImageFitType.TYPE_WIDTH) :
  dimensionWH;

5. 约束动画实现

5.1 约束和动画函数

export function constrainOffsetAndAnimation(
  info: ConstrainOffsetAndAnimationType
): [boolean, boolean] {
    if (info.dimensionWH === ImageFitType.TYPE_DEFAULT) {
        return [false, false];
    }
    
    const WIN_SIZE = windowSizeManager.get();
    const IMG_SIZE = getImgSize(
      info.imageDefaultSize,
      info.rotate,
      info.dimensionWH
    );
    
    // 获取当前偏移量
    let currentOffset = info.imageOffsetInfo[
      `last${info.dimensionWH === ImageFitType.TYPE_WIDTH ? 'X' : 'Y'}`
    ];
    
    // 处理列表偏移
    if (info.dimensionWH === (
      info.listDirection === Axis.Horizontal ? 
        ImageFitType.TYPE_WIDTH : 
        ImageFitType.TYPE_HEIGHT
    )) {
        currentOffset += info.imageListOffset;
    }
    
    // 计算约束后的偏移量
    const CLAMPED_OFFSET = constrainOffset(
      currentOffset,
      WIN_SIZE[info.dimensionWH],
      IMG_SIZE,
      info.scaleValue
    );
    
    // 处理偏移量变化
    if (CLAMPED_OFFSET !== currentOffset) {
        let updateFn = () => {
            info.imageOffsetInfo[
              `current${info.dimensionWH == ImageFitType.TYPE_WIDTH ? 'X' : 'Y'}`
            ] = CLAMPED_OFFSET;
            info.imageOffsetInfo.stash();
        };
        
        runWithAnimation(updateFn);
        
        // 检查是否需要切换图片
        if (isToggle(
          currentOffset,
          WIN_SIZE[info.dimensionWH],
          IMG_SIZE,
          info.scaleValue,
          info.TogglePercent
        )) {
            const BOL = currentOffset >= 0;
            return [BOL, !BOL];
        }
    }
    
    return [false, false];
}

5.2 使用示例

// 处理图片约束和动画
const [leftExceeded, rightExceeded] = constrainOffsetAndAnimation({
    dimensionWH: ImageFitType.TYPE_WIDTH,
    imageDefaultSize: imageSize,
    imageOffsetInfo: offsetModel,
    scaleValue: scale,
    rotate: rotation,
    TogglePercent: 0.2,
    imageListOffset: listOffset,
    listDirection: Axis.Horizontal
});

// 根据结果处理图片切换
if (leftExceeded) {
    // 切换到上一张
    switchToPrevious();
} else if (rightExceeded) {
    // 切换到下一张
    switchToNext();
}

6. 最佳实践

6.1 性能优化

  1. 缓存计算结果
const maxOffset = getMaxAllowedOffset(winSize, imageSize, scale);
// 多次使用maxOffset而不是重复计算
  1. 避免频繁更新
// 使用防抖处理频繁的约束计算
const debouncedConstrain = debounce((info) => {
    constrainOffsetAndAnimation(info);
}, 16);

6.2 错误处理

function safeConstrainOffset(info: ConstrainOffsetAndAnimationType) {
    try {
        return constrainOffsetAndAnimation(info);
    } catch (error) {
        console.error('Constrain calculation failed:', error);
        return [false, false];
    }
}

通过合理使用图片约束处理,可以实现流畅的图片浏览体验。在实际开发中,要注意性能优化和边界情况处理,确保图片操作的准确性和流畅性。

收藏00

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