HarmonyOS鸿蒙Next中怎么做出“智感握姿”的动画?

HarmonyOS鸿蒙Next中怎么做出“智感握姿”的动画? 虽然系统开放了左手和右手的握持检测的API,但还需要实现按钮从一侧消失,再从另一侧出现的动画,该如何实现?

cke_5326.png


更多关于HarmonyOS鸿蒙Next中怎么做出“智感握姿”的动画?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

真机效果图:

cke_156.gif

动画实现思路:

检测到切换手握持后,先让控件消失,然后在动画结束时将控件切换到另一边,最后让控件出现。

完整代码:

需要先在 entry/src/main/module.json5 下配置 ohos.permission.DETECT_GESTURE 权限并向用户申请,具体可看:怎么实现 Mate80 系列同款握持检测?

// 从鸿蒙多模态感知 Kit 中引入 motion 模块,用于监听握持状态
import { motion } from '@kit.MultimodalAwarenessKit';

@Entry
@ComponentV2
struct FloatComponent {
  /* ========================= 状态变量 ========================= */
  // 控制悬浮按钮是否可见
  @Local isVisible: boolean = true;
  // 控制悬浮按钮在左侧还是右侧
  @Local isPositionedLeft: boolean = true;

  /* ========================= 握持状态缓存 ========================= */
  // 上一次握持状态(防抖用)
  private oldHandStatus = motion.HoldingHandStatus.NOT_HELD;
  // 最新一次握持状态(防抖用)
  private newHandStatus = motion.HoldingHandStatus.NOT_HELD;
  // 防抖锁:true 表示可以响应新事件,false 表示正在防抖中
  private isDebouncing: boolean = true;

  /* ========================= 防抖 & 切换逻辑 ========================= */
  /**
   * 真正执行业务逻辑的函数:
   * 1. 隐藏按钮(500ms动画)
   * 2. 切换左右位置
   * 3. 重新显示按钮(500ms动画)
   * 4. 1.5s防抖:期间若状态再次变化则递归调用,否则释放防抖锁
   */
  private processHandHeldChange = (data: motion.HoldingHandStatus) => {
    // 1.5s后检查:如果期间状态又变了,则继续递归防抖;否则释放锁
    setTimeout(() => {
      if (this.newHandStatus != this.oldHandStatus) {
        this.oldHandStatus = this.newHandStatus;
        this.processHandHeldChange(data);
      } else {
        this.isDebouncing = true; // 释放防抖锁
      }
    }, 1500);

    // 立即隐藏按钮
    this.isVisible = false;

    // 500ms后切换左右并重新显示(与隐藏动画衔接)
    setTimeout(() => {
      this.isPositionedLeft = !this.isPositionedLeft;
      this.isVisible = true;
    }, 500);
  };

  /* ========================= 握持事件回调 ========================= */
  /**
   * 监听“握持手改变”事件:
   * - 若状态无变化则直接返回
   * - 仅当左手或右手握持时才触发业务逻辑
   * - 通过防抖锁避免1.5s内重复触发
   */
  private onHandStatusChanged: Callback<motion.HoldingHandStatus> = (
    data: motion.HoldingHandStatus
  ) => {
    // 状态未变,无需处理
    if (this.oldHandStatus == data) return;

    // 只关心“左手握持”或“右手握持”
    if (
      data == motion.HoldingHandStatus.LEFT_HAND_HELD ||
        data == motion.HoldingHandStatus.RIGHT_HAND_HELD
    ) {
      this.newHandStatus = data;
      if (!this.isDebouncing) return; // 防抖中,直接丢弃
      this.isDebouncing = false; // 加锁
      this.oldHandStatus = data; // 更新缓存
      this.processHandHeldChange(data); // 执行业务
    }
  };

  /* ========================= 生命周期 ========================= */
  aboutToAppear(): void {
    try {
      // 注册握持状态监听
      motion.on('holdingHandChanged', this.onHandStatusChanged);
      console.info('on succeeded');
    } catch (e) {
      console.error('Failed on; err code = ' + e.code);
    }
  }

  aboutToDisappear(): void {
    try {
      // 页面销毁时移除监听,防止内存泄漏
      motion.off('holdingHandChanged'); // 移除所有同类订阅
      console.info('off succeeded');
    } catch (e) {
      console.error('Failed off; err code = ' + e.code);
    }
  }

  /* ========================= UI ========================= */
  build() {
    // 根据 isPositionedLeft 决定按钮在左还是右
    Stack({
      alignContent: this.isPositionedLeft ? Alignment.Start : Alignment.End,
    }) {
      // 仅当可见时才渲染按钮
      if (this.isVisible) {
        Button({ type: ButtonType.Circle, stateEffect: true }) {
          SymbolGlyph($r('sys.symbol.camera')); // 相机图标
        }
        .borderRadius(16)
        .clickEffect({ level: ClickEffectLevel.MIDDLE, scale: 0.8 })
        .size({ width: 40, height: 40 })
        .backgroundColor($r('sys.color.multi_color_aux_03'))
        .margin(20)
        // 切换左右时的滑入动画
        .transition(
          TransitionEffect.move(
            this.isPositionedLeft ? TransitionEdge.START : TransitionEdge.END
          ).animation({ duration: 500, curve: Curve.Ease })
        );
      }
    }
    .width('100%')
    .height('100%');
  }
}

更多关于HarmonyOS鸿蒙Next中怎么做出“智感握姿”的动画?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中实现“智感握姿”动画,需使用ArkUI的动画能力。主要步骤包括:

  1. 通过传感器(如陀螺仪、加速度计)监听设备握持姿态数据。
  2. 使用属性动画(如animateTo)或帧动画(KeyframeAnimation)关联传感器数据与UI元素(如图标、控件)的旋转、位移或缩放。
  3. 结合状态管理(如@State)动态更新动画参数,实现流畅的交互反馈。
    注意:需在module.json5中声明传感器权限,并调用@ohos.sensor接口获取数据。

在HarmonyOS Next中实现“智感握姿”动画,可以结合系统提供的握持检测API与ArkUI的动画能力。核心思路是:监听握持状态变化,并触发对应的组件位移动画。

以下是关键步骤和代码示例:

  1. 导入握持检测模块并申请权限module.json5中申请ohos.permission.DETECT_HOLDING_POSTURE权限,并在代码中导入[@ohos](/user/ohos).sensor.holdingPostureDetection模块。

  2. 监听握持状态变化 使用on('holdingPostureChange')监听握持状态。回调事件中可获取当前握持方向(左手、右手或无握持)。

    import { holdingPostureDetection } from '[@ohos](/user/ohos).sensor.holdingPostureDetection';
    
    // 注册监听
    holdingPostureDetection.on('holdingPostureChange', (data) => {
      if (data.holdingPosture === holdingPostureDetection.HoldingPosture.LEFT_HAND) {
        // 触发左手握持动画:按钮从右侧消失,左侧出现
        this.triggerAnimation('left');
      } else if (data.holdingPosture === holdingPostureDetection.HoldingPosture.RIGHT_HAND) {
        // 触发右手握持动画:按钮从左侧消失,右侧出现
        this.triggerAnimation('right');
      }
    });
    
  3. 实现位移动画 使用ArkUI的显式动画(如animateTo)控制按钮的位置属性。通过改变组件的translateoffset属性,并结合透明度变化,实现“消失-出现”效果。

    // 以Column布局中的按钮为例
    [@State](/user/State) btnOffsetX: number = 0;
    [@State](/user/State) btnOpacity: number = 1;
    
    triggerAnimation(direction: string) {
      // 第一步:按钮向屏幕外平移并淡出
      animateTo({
        duration: 200,
        curve: Curve.EaseOut
      }, () => {
        this.btnOpacity = 0;
        this.btnOffsetX = (direction === 'left') ? 100 : -100; // 根据方向平移
      });
      
      // 第二步:重置位置到另一侧,并平移回屏幕内淡入
      setTimeout(() => {
        this.btnOffsetX = (direction === 'left') ? -100 : 100; // 先置于另一侧外
        animateTo({
          duration: 200,
          curve: Curve.EaseIn
        }, () => {
          this.btnOpacity = 1;
          this.btnOffsetX = 0; // 平移回原位
        });
      }, 200);
    }
    

    在UI布局中,将动画属性绑定到按钮组件:

    Column() {
      Button('按钮')
        .opacity(this.btnOpacity)
        .translate({ x: this.btnOffsetX })
    }
    
  4. 优化体验

    • 可结合系统握持检测的灵敏度设置,避免频繁触发。
    • 使用Curve曲线优化动画流畅度。
    • 在动画过程中可考虑禁用按钮交互,避免操作冲突。

通过以上步骤,即可实现根据握持方向触发的按钮位置切换动画。注意在实际测试中调整动画时长和位移距离,以匹配具体设计需求。

回到顶部