HarmonyOS 鸿蒙Next交互归一开发指导

HarmonyOS 鸿蒙Next交互归一开发指导

概述

在移动应用开发中,悬浮、点击、双击、长按、上下文菜单、拖拽、轻扫、滚动/平移、缩放和旋转这10种交互事件,在不同的移动端设备上可以分别由触控屏、触控板或鼠标这三类输入设备的不同操作方式触发。开发多设备项目时,必须考虑不同输入设备的交互方式。而使用交互归一组件,保证不同交互场景下的体验一致性,开发者只需要调用归一后的交互事件接口,无需为每个输入设备单独适配,从而大幅简化开发流程。

如下图为不同交互事件在不同设备上的触发方式:

图片

如下表为不同框架上提供的交互归一组件实现不同交互事件的接口:

RN(组件地址) Flutter(组件地址 H5(组件地址
悬浮 Gesture.Hover() onHover onHover
点击 Gesture.Pan() onTap onClick
双击 Gesture.Tap() onDoubleTap onDoubleClick
长按 Gesture.LongPress() onLongPress onLongPressStart
onLongPressEnd
onLongPressCancel
上下文菜单 react-native-popup-menu onContentMenu onContextMenu
拖拽 Gesture.Pan() onDragStart
onDragUpdate
onDragEnd
onDragStart
onDragEnter
onDragMove
onDragLeave
onDrop
轻扫 Gesture.Fling() onSwipe onSwipe
滚动 Gesture.Pan() onPanStart
onPanUpdate
onPanEnd
onPanCancel
onScroll
缩放 Gesture.Pinch() Transform
onPinchStart
onPinchUpdate
onPinchStart
onPinchMove
onPinchEnd
旋转 Gesture.Rotation() Transform
onRotateStart
onRotateUpdate
onRotateEnd
onRotateStart
onRotateMove
onRotateEnd

交互归一事件适配

一、悬浮事件

  • RN适配指导

    1. 主要方法和参数

    Gesture.Hover():悬浮手势对象。

    onHover:悬浮手势触发的回调方法。

    2. 示例

import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; 

// 用手势组件包裹元素 
<GestureDetector gesture={onHoverForTest}> 
  <Text style={[isHovered && styles.mouseHovered]}> 
    {title} 
  </Text> 
</GestureDetector> 

//在鼠标悬浮的时候改变样式 
 const onHoverForTest = Gesture.Hover().onHover(e => { 
    // 鼠标移入或移除的时候触发 
    setIsHovered(e.isHover); 
  });
  • Flutter适配指导

    1. 主要方法

    onHover:悬浮事件名,在onHover方法实现悬浮需要实现的具体事件效果。

    2. 回调参数

    isHover:鼠标是否悬浮。

    3. 示例

UnifiedGestureDetector( 
  onHover: onHover, 
  child: Container(...) //需要实现悬浮效果的widget,例如Text 
) 
void onHover(bool isHover, PointerEvent event) { 
  if (mounted) { 
    setState(() { 
       if (isHover) {  
         // 悬浮,按钮变大逻辑 
       }else { 
         // 取消悬浮,按钮还原 
        }   
     }); 
  } 
}
  • H5适配指导

    1. 主要方法

    onHover:悬浮进入或退出事件。

    onHoverMove:悬浮事件,在onHoverMove方法实现悬浮的具体效果。

    2. 示例

<template> 
  <div ref="testDom" id="testId"></div> 
</template> 
<script lang="ts" setup> 
import { onMounted, onUnmounted, ref } from "vue"; 
import { 
  PointerGestureManager, 
  PointerOptions, 
  GestureHandlers, 
  PointerState, 
} from "@hadss/web_uni_input"; 
const handleHover = (state: PointerState) => { 
  // 代码编辑 
}; 
const handleHoverMove = (state: PointerState) => { 
  // 代码编辑 
}; 
const testDom = ref<HTMLElement | null>(null); 
const instance = ref(null); 
onMounted(() => { 
  // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 
  const handlers: GestureHandlers = { 
    onHover: handleHover, 
    onHoverMove: handleHoverMove, 
  }; 
  const configs: PointerOptions = { 
    enableHover: true, 
  }; 
  if (testDom.value) { 
    instance.value = PointerGestureManager(testDom.value, handlers, configs); 
  } 
}); 
onUnmounted(() => { 
  //destroy销毁实例,实例销毁以后交互归一事件不再触发 
  if (instance.value) { 
    instance.value.destroy(); 
  } 
}); 
</script> 
<style scoped> 
#testId { 
  width: 200px; 
  height: 200px; 
  background-color: aquamarine; 
} 
</style>

2、点击和双击事件

  • RN适配指导

    1. 主要方法和参数

    Gesture.Tap():手势点击对象,单击或双击的时候触发。

    numberOfTaps:属性,用于触发点击手势所需的点击次数。

    minPointers:属性,用于触发手势需要的手指数目。

    onStart:回调方法,手势触发开始时的回调。

    2. 示例

import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; 

// 用手势组件包裹元素 
<GestureDetector gesture={Gesture.Exclusive(doubleTap, singleTap)}> 
  <View> 
    <Animated.View style={[animatedStyle]}> 
      {songsList.map((item, index) => ( 
        <View key={index}> 
          <Text>1233333333333333</Text> 
        </View> 
      ))} 
    </Animated.View> 
  </View> 
</GestureDetector> 

// 通过点击的次数区分单双击事件 
// 单击事件 
const singleTap = Gesture.Tap() 
  .numberOfTaps(1) 
  .onStart(() => { 
    console.log('Single tap!'); 
  }); 
// 双击事件 
const doubleTap = Gesture.Tap() 
  .numberOfTaps(2) 
  .onStart(() => { 
    console.log('Double tap!') 
  });
  • Flutter适配指导

    1. 主要方法

    onTap:单击事件名,在onTap方法实现单击具体操作。

    onDoubleTap:双击事件名,在onDoubleTap方法实现双击具体操作。

    2. 示例

UnifiedGestureDetector( 
  onTap: onTap, 
  onDoubleTap: onDoubleTap, 
  child: Container(...) //需要实现单击和双击的widget 
) 
void onTap() { 
    //单击进入歌曲详情页,歌曲暂停状态下不播放歌曲 
} 
void onDoubleTap() { 
    //双击进入歌曲详情页,歌曲暂停状态下播放歌曲 
}
  • H5适配指导

    1. 主要方法

    onClick:单击事件,在onClick方法实现单击具体操作。

    onDoubleClick:双击事件,在onDoubleClick方法实现双击具体操作。

    2. 示例

<template> 
  <div ref="testDom" id="testId"></div> 
</template> 
<script lang="ts" setup> 
import { onMounted, onUnmounted, ref } from "vue"; 
import { 
  PointerGestureManager, 
  PointerOptions, 
  GestureHandlers, 
  PointerState, 
} from "@hadss/web_uni_input"; 
const handleClick = (state: PointerState) => { 
  // 代码编辑 
}; 
const handleDoubleClick = (state: PointerState) => { 
  // 代码编辑 
}; 
const testDom = ref<HTMLElement | null>(null); 
const instance = ref(null); 
onMounted(() => { 
  // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 
  const handlers: GestureHandlers = { 
    onClick: handleClick, // 点击 
    onDoubleClick: handleDoubleClick // 双击 
  }; 
  const configs: PointerOptions = { 
    enableClick: true, 
    enableDoubleClick: true, 
  }; 
  if (testDom.value) { 
    instance.value = PointerGestureManager(testDom.value, handlers, configs); 
  } 
}); 
onUnmounted(() => { 
  //destroy销毁实例,实例销毁以后交互归一事件不再触发 
  if (instance.value) { 
    instance.value.destroy(); 
  } 
}); 
</script> 
<style scoped> 
#testId { 
  width: 200px; 
  height: 200px; 
  background-color: aquamarine; 
} 
</style>

3、长按事件

  • RN适配指导

    1. 主要方法和参数

    Gesture.LongPress():长按事件对象,长按时创建。

    repeat:boolean类型属性,是否允许长按手势重复触发。

    minDuration:number类型属性,长按手势识别所需的最短持续时间(毫秒)。

    onStart:回调方法,手势开始时的回调。

    onCancel:回调方法,手势取消时的回调。

    onEnd:回调方法,手势结束时的回调。

    2. 示例

import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; 

// 用手势组件包裹元素 
<GestureDetector gesture={longPressGesture}> 
  <Image 
    source={require('../../../asset/share.svg')} 
    style={styles.imageSmall} 
  /> 
</GestureDetector> 
// 长按的时候触发提醒 
const longPressGesture = Gesture.LongPress().onEnd(() => Alert.alert('无法分享'));
  • Flutter适配指导

    1. 主要方法

    onLongPress:长按事件名,在onLongPress方法中实现长按需要的效果。

    2. 示例

UnifiedGestureDetector( 
  pointerOptions: const PointerOptions(), 
  onLongPress: onLongPress, 
  child:  Container(...) //需要实现长按效果的widget 
) 
void onLongPress() { 
    //长按事件触发后的处理逻辑 
}
  • H5适配指导

    1. 主要方法

    onLongPressStart:长按开始事件,在onLongPressStart方法实现长按的具体操作。

    onLongPressEnd:长按结束事件。

    onLongPressCancel:长按取消事件,在onLongPressCancel方法实现长按取消的具体操作。

    2. 示例

<template> 
  <div ref="testDom" id="testId"></div> 
</template> 
<script lang="ts" setup> 
import { onMounted, onUnmounted, ref } from "vue"; 
import { 
  PointerGestureManager, 
  PointerOptions, 
  GestureHandlers, 
  PointerState, 
} from "@hadss/web_uni_input"; 
const handlePressStart = (state: PointerState) => { 
  // 代码编辑 
}; 
const handlePressEnd = (state: PointerState) => { 
  // 代码编辑 
}; 
const handlePressCancel = (state: PointerEvent) => { 
  // 代码编辑 
}; 
const testDom = ref<HTMLElement | null>(null); 
const instance = ref(null); 
onMounted(() => { 
  // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 
  const handlers: GestureHandlers = { 
    onLongPressStart: handlePressStart, // 长按开始 
    onLongPressEnd: handlePressEnd, // 长按结束 
    onLongPressCancel: handlePressCancel, // 长按取消 
  }; 
  const configs: PointerOptions = { 
    enableLongPress: true, 
  }; 
  if (testDom.value) { 
    instance.value = PointerGestureManager(testDom.value, handlers, configs); 
  } 
}); 
onUnmounted(() => { 
  // destroy销毁实例,实例销毁以后交互归一事件不再触发 
  if (instance.value) { 
    instance.value.destroy(); 
  } 
}); 
</script> 
<style scoped> 
#testId { 
  width: 200px; 
  height: 200px; 
  background-color: aquamarine; 
} 
</style>

4、上下文菜单

  • RN适配指导

    1. 组件

    MenuTrigger: 组件,用于嵌套在触发上下文的组件的外层。

    MenuOptions: 组件,用于嵌套在上下文组件的外层,其内层可以有多个MenuOption 组件。

    Menu: 组件,上下文外层组件,用于嵌套在MenuTrigger 和MenuOptions组件外。

    MenuProvider: 组件,上下文外层组件,用于嵌套在Menu组件外。

    2. 示例

import { 
  GestureDetector, 
  Gesture, 
  MenuProvider, 
  Menu, 
  MenuOptions, 
  MenuOption, 
  MenuTrigger, 
  ViewWithKeyEvent, 
} from '@hadss/react-native-uniinput'; 

//MenuTrigger播过触发上下文的组件    
//MenuOptions包裹弹出的上下文的内容 
//MenuTrigger和MenuTrigger都是Menu的子组件,而Menu又是MenuProvider的子组件 
<MenuProvider 
  style={{alignItems: 'center', marginTop: 20}} 
  onTouchStart={calculateMenuPosition}> 
  <Menu 
    onClose={() => { 
      setTimeout(() => setIsLongPressed(false), 500); 
    }}> 
    <MenuTrigger 
      triggerOnLongPress={true} 
      onPress={() => { 
        setIsLongPressed(true); 
      }}> 
      <Image 
        source={require('../../../../asset/song_item_icon.svg')} 
        style={styles.songIcon} 
      /> 
    </MenuTrigger> 
    <MenuOptions 
      optionsContainerStyle={[ 
        styles.optionList, 
        { 
          position: 'absolute', 
          top: position.top, 
          left: position.left, 
        }, 
      ]}> 
      <MenuOption 
        onSelect={() => deleteItem(index)} 
        style={{flexDirection: 'row'}}> 
        <Image 
          source={require('../../../../asset/delete.svg')} 
          style={styles.songDelete} 
        /> 
        <Text style={styles.optionBtn}>{'删除'}</Text> 
      </MenuOption> 
      {item.hasCollect ? ( 
        <MenuOption 
          onSelect={() => deleteCollectItem(index)} 
        style={{flexDirection: 'row'}}> 
          <Image 
            source={require('../../../../asset/deleteCollect.svg')} 
            style={styles.songDelete} 
          /> 
          <Text style={styles.optionBtn}>{'移除收藏'}</Text> 
        </MenuOption> 
      ) : ( 
        <MenuOption 
          onSelect={() => collectItem(index)} 
          style={{flexDirection: 'row'}}> 
          <Image 
            source={require('../../../../asset/collect.svg')} 
            style={styles.songDelete} 
          /> 
          <Text style={styles.optionBtn}>{'收藏到歌单'}</Text> 
        </MenuOption> 
      )} 
    </MenuOptions> 
  </Menu> 
</MenuProvider>
  • Flutter适配指导

    1. 主要方法

    onContentMenu:下拉菜单功能,鼠标或者触控点位置存在的情况下,显示上下文菜单UI效果。

    2. 回调参数

    event.localPosition:当前鼠标或者触控点位置。

    3. 示例

UnifiedGestureDetector( 
  pointerOptions: const PointerOptions(), 
  onContentMenu: onContentMenu, 
  child: CustomWidget(...) //需要实现上下文菜单的widget 
) 
void onContentMenu(GestureEvent event) { 
  //event.localPosition:当前鼠标或者触控点的位置 
  if (event.localPosition == null) { 
    return; 
  } 
  //创建上下文菜单Widget,使用PopupMenu的showMenu方法自定义PopupMenuItem实现上下文菜单UI 
}
  • H5适配指导

    1. 主要方法

    onContextMenu:下拉菜单功能,鼠标或者触控点位置存在的情况下,显示上下文菜单UI效果。

    2. 示例

<template> 
  <div ref

更多关于HarmonyOS 鸿蒙Next交互归一开发指导的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

鸿蒙Next交互归一开发基于ArkTS语言,通过声明式UI和状态管理实现跨设备统一交互。开发者需使用ArkUI组件构建自适应界面,结合分布式能力实现多端协同。系统提供统一的交互事件处理机制,支持一次开发多端部署。关键API包括UI上下文管理、交互事件响应及布局自适应模块。

更多关于HarmonyOS 鸿蒙Next交互归一开发指导的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next的交互归一开发指导提供了跨设备交互事件的一致性解决方案,通过统一的API接口适配触控屏、触控板和鼠标等不同输入设备。该方案覆盖了悬浮、点击、双击、长按、上下文菜单、拖拽、轻扫、滚动/平移、缩放和旋转等10种核心交互事件,并针对RN、Flutter和H5框架分别提供了具体的组件和接口实现。

关键点包括:

  1. 统一接口设计:不同框架下的事件接口命名和参数保持一致(如onHover、onTap等),减少多设备适配成本。
  2. 框架适配示例:详细展示了RN(Gesture组件)、Flutter(UnifiedGestureDetector)和H5(PointerGestureManager)的代码实现,包括事件绑定和回调处理。
  3. 输入设备兼容:支持触控、鼠标和键盘事件的无缝切换,例如通过ViewWithKeyEvent处理物理按键。
  4. 性能优化:通过事件管理器的销毁机制(如destroy())避免资源泄漏,确保交互响应的流畅性。

开发者可直接参考提供的代码示例和组件地址(如GitCode仓库),快速集成到多设备项目中,无需针对不同输入方式单独开发,显著提升开发效率。

回到顶部