交互归一开发指导
概述
在移动应用开发中,悬浮、点击、双击、长按、上下文菜单、拖拽、轻扫、滚动/平移、缩放和旋转这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 |
交互归一事件适配
1、悬浮事件
- 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="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 handleContextMenu = (state: MouseEvent) => { // 代码编辑 }; const testDom = ref<HTMLElement | null>(null); const instance = ref(null); onMounted(() => { // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 const handlers: GestureHandlers = { onContextMenu: handleContextMenu, // 上下文菜单 }; const configs: PointerOptions = { enableContextMenu: 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>
5、拖拽事件
- RN适配指导
1. 主要方法和参数
Gesture.Pan():手势拖拽对象。
minDistance:number类型属性,触发拖拽手势所需的最小距离。
minPointers:number类型属性,触发拖拽手势需要的手指数目。
direction:string类型属性,定义手势的方向或方向组合, 可能的值有:'all', 'horizontal', 'vertical', 'left', 'right', 'up', 'down', 'none' 。也可以使用&和|组合。
onStart:回调方法,手势拖拽开始时的回调。
onUpdate:回调方法,手势拖拽变化时的回调。
onCancel:回调方法,手势拖拽取消时的回调。
onEnd:回调方法,手势拖拽结束时的回调。
2. 示例
import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; //手势组件包裹需要进行拖动的内容 <GestureDetector gesture={panProgress}> <View> <View style={[styles.progressFill, {width: `${position}%`}]} /> </View> </GestureDetector const panProgress = Gesture.Pan() .minPointers(1) .direction('left | right') .onUpdate(event => { console.log('Gesture Update:', event); }) const styles = StyleSheet.create({ progressFill: { height: '100%', backgroundColor: 'rgba(255, 255, 255, 0.8)', borderRadius: 5, }, })
- Flutter适配指导
1. 主要方法
onDragStart:拖拽开始。
onDragUpdate:拖拽中,更新进度条宽度,localPosition返回拖拽的坐标。
onDragEnd:拖拽结束,播放器播放指定进度,刷新页面。
2. 回调参数
detail.localPosition.dx:拖拽的x轴坐标。
detail.localPosition.dy:拖拽的y轴坐标。
3. 示例
UnifiedGestureDetector( pointerOptions: const PointerOptions( enableRotate: false, ), onDragStart: onDragStart, onDragUpdate: onDragUpdate, onDragEnd: onDragEnd, child: Container(...) //自定义拖拽的控件 ) void onDragStart(DragStartDetails detail) {} void onDragUpdate(DragUpdateDetails detail) { //detail.localPosition.dx拖拽x轴坐标,根据x轴坐标更新播放器进度条,控制拖拽范围[0,进度条控件宽度] } void onDragEnd(DragEndDetails detail) { //拖拽结束获取最后x轴坐标位置,计算当前进度百分比,调整播放器进度 }
- H5适配指导
1. 主要方法
onDragStart:拖拽开始事件,绑定A组件,在触控屏上长按并移动或长按鼠标左键并移动触发。
onDragEnter:拖拽进入事件,绑定B组件,进入B组件时触发。
onDragMove:拖拽移动事件,绑定B组件,在B组件移动时触发。
onDragLeave:拖拽离开事件,绑定B组件,离开B组件时触发。
onDrop:拖拽结束事件,松开鼠标左键或手指在触控屏抬起触发。
2. 示例
<template> <div id="testId"> <div ref="dragStart" draggable="true" class="dragStart"></div> <div ref="drag" class="drag"></div> </div> </template> <script lang="ts" setup> import { onMounted, onUnmounted, ref } from "vue"; import { PointerGestureManager, PointerOptions, GestureHandlers, PointerState, } from "@hadss/web_uni_input"; const dragStart = ref<HTMLElement | null>(null); const drag = ref<HTMLElement | null>(null); const instance1 = ref(null); const instance2 = ref(null); const handleDragStart = (state: DragEvent) => { // 代码编辑 }; const handleDragEnter = (state: DragEvent) => { // 代码编辑 }; const handleDragMove = (event: DragEvent) => { event.preventDefault(); // 代码编辑 }; const handleDragLeave = (state: DragEvent) => { // 代码编辑 }; const handleDrop = (state: DragEvent) => { // 代码编辑 }; onMounted(() => { // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 const handlers1: GestureHandlers = { onDragStart: handleDragStart, // 拖拽开始 }; const handlers2: GestureHandlers = { onDragEnter: handleDragEnter, // 拖拽进入 onDragMove: handleDragMove, // 拖拽中 onDragLeave: handleDragLeave, // 拖拽离开 onDrop: handleDrop, // 拖拽放下 }; const configs: PointerOptions = { enableDrag: true, }; if (dragStart.value) { instance1.value = PointerGestureManager(dragStart.value, handlers1, configs); } if (drag.value) { instance2.value = PointerGestureManager(drag.value, handlers2, configs); } }); onUnmounted(() => { // destroy销毁实例,实例销毁以后交互归一事件不再触发 if (instance1.value) { instance1.value.destroy(); } if (instance2.value) { instance2.value.destroy(); } }); </script> <style scoped> #testId { width: 100%; height: 900px; } .dragStart { width: 100px; height: 100px; background-color: aquamarine; } .drag { width: 100px; height: 100px; background-color: red; } </style>
6、轻扫事件
- RN适配指导
1. 主要方法和参数
Gesture.Fling(): 手势轻扫对象。
minPointers: number类型属性,触发手势需要的手指数目。
direction:定义手势的方向或方向组合, 可能的值有:'all', 'horizontal', 'vertical', 'left', 'right', 'up', 'down', 'none' 。也可以使用'&'和'|'组合。
onStart: 回调方法,手势轻扫开始时的回调。
onCancel: 回调方法,手势轻扫取消时的回调。
2. 示例
import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; //手势组件包裹需要进行拖动的内容 <GestureDetector gesture={flingSongsList}> <Animated.View > {songsList.map((item, index) => ( <View key={index} style={styles.item}> <Text>1233333333333333</Text> </View> ))} </Animated.View> </GestureDetector> const panSongsList = Gesture.Fling() .minVelocity(200) .onStart(() => { // 处理轻扫事件回调 });
- Flutter适配指导
1. 主要方法
onSwipe:轻扫事件,可以设置pointerOptions属性,在轻扫的时候禁掉其他手势行为,例如缩放 enableRotate属性可以设置为false。
2. 主要方法
event.speed:可以根据属性来约束轻扫的速度,单位为db/s,示例中speed大于等于600才判定为轻扫操作,执行轻扫功能。
event.angle:滑动角度,顺时针旋转为0度到180度,逆时针旋转为-180度到0度,根据角度正负判断向上轻扫还是向下轻扫。
3. 示例
UnifiedGestureDetector( pointerOptions: PointerOptions( speed: 150, direction: SwipeDirection.all, enableSwipe: true, panDirection: panDirection, ), onSwipe: onSwipe, child: ListView(...) //自定义轻扫控件,可以自定义一个ListView实现列表滚动 ) void onSwipe(GestureEvent event) { //约束轻扫条件:滑动速度大于等于600才能判定为轻扫 if (event.speed! < 600) { return; } //注意:手势轻扫和鼠标滚动一格获取的event.angle取值有差异,根据用户设置鼠标滚轮上下滚动调整,存在鼠标向上滚动event.angle<0,具体根据pc鼠标设置调整 if (event.angle > 0){ //向上轻扫 }else{ //向下轻扫 } }
- H5适配指导
1. 主要方法
onSwipe:轻扫事件,onSwipe和onScroll不要同时使用,会存在冲突。
2. 示例
<template> <div id="testId" ref="testDom"></div> </template> <script lang="ts" setup> import { onMounted, onUnmounted, ref } from "vue"; import { PointerGestureManager, PointerOptions, GestureHandlers, PointerState, } from "@hadss/web_uni_input"; const testDom = ref<HTMLElement | null>(null); const instance = ref(null); const handleSwipe = (state: PointerState) => { // 代码编辑 }; onMounted(() => { // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 const handlers: GestureHandlers = { onSwipe: handleSwipe, // 轻扫 }; const configs: PointerOptions = { enableSwipe: true, }; if (testDom.value) { instance.value = PointerGestureManager(testDom.value, handlers, configs); } }); onUnmounted(() => { // destroy销毁实例,实例销毁以后交互归一事件不再触发 if (instance.value) { instance.value.destroy(); } }); </script> <style scoped> #testId { width: 100%; height: 900px; background-color: aquamarine; } </style>
7、滚动/平移事件
- RN适配指导
1. 主要方法和参数
Gesture.Pan():手势滚动对象。
minDistance:number类型属性,触发拖动手势所需的最小距离。
minPointers:number类型属性,触发拖动手势需要的手指数目。
direction:string类型属性,定义手势的方向或方向组合, 可能的值有:'all', 'horizontal', 'vertical', 'left', 'right', 'up', 'down', 'none' 。也可以使用'&'和'|'组合。
onStart:回调方法,手势拖动开始时的回调。
onUpdate:回调方法,手势拖动变化时的回调。
onCancel:回调方法,手势拖动取消时的回调。
onEnd:回调方法,手势拖动结束时的回调。
2. 示例
import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; //手势组件包裹需要进行拖动的内容 <GestureDetector gesture={panSongsList}> <Animated.View > {songsList.map((item, index) => ( <View key={index} style={styles.item}> <Text>1233333333333333</Text> </View> ))} </Animated.View> </GestureDetector> const panSongsList = Gesture.Pan() .minDistance(150) .onStart(() => { console.log('开始拖动'); })
- Flutter适配指导
1. 主要方法
onPanStart:滚动开始。
onPanUpdate:滚动中,根据event.offsetY判断向上滚动还是向下滚动。
onPanEnd:滚动结束,重置页面行为,例如同页面轻扫功能在滚动的时候禁止,此时可以放开限制。
onPanCancel:滚动取消。
2. 回调参数
event.velocityX:当前手势的x轴方向速度,单位为db/s,从左往右为正,反之为负。
event.velocityY:当前手势的y轴方向速度,单位为db/s,从上而下为正,反之为负。
event.offsetX:手势事件偏移量X,单位为vp,从左往右滑动offsetX为正,反之为负。
event.offsetY:手势事件偏移量Y,单位为vp,从上往下滑动offsetY为正,反之为负。
3. 示例
UnifiedGestureDetector( pointerOptions: PointerOptions( speed: 150, direction: SwipeDirection.all, enableSwipe: false, enablePan: true, panDirection: panDirection, ), onPanStart: onPanStart, onPanUpdate: onPanUpdate, onPanEnd: onPanEnd, onPanCancel: onPanCancel, child: //自定义滚动控件,可以自定义一个ListView实现列表滚动 ); void onPanStart(GestureEvent event) {} void onPanUpdate(GestureEvent event) { if (event.offsetX == null || event.offsetY == null) { return; } //约束滚动行为 //上滑:y轴速度大于-600小于-15为上滑 //下滑:y轴速度大于15且小于600为下滑 if (event.velocityY! < 600 && event.velocityY! > -600) { if (event.velocityY! > 15 || event.velocityY! < -15) { if (event.offsetY! < 0) { //上滑:根据offsetY设置widget的offset } else { //下滑:根据offsetY设置widget的offset } } } } void onPanEnd(GestureEvent event) {} void onPanCancel(GestureEvent event) {}
- H5适配指导
1. 主要方法
onScroll:滚动事件,PC端根据滚轮的滚动或者手机端根据手势的移动进行触发,以此实现相应的滚动效果。
2. 示例
<template> <div id="testId" ref="testDom"></div> </template> <script lang="ts" setup> import { onMounted, onUnmounted, ref } from "vue"; import { PointerGestureManager, PointerOptions, GestureHandlers, PointerState, } from "@hadss/web_uni_input"; const testDom = ref<HTMLElement | null>(null); const instance = ref(null); const handleScroll = (state: PointerState) => { // 代码编辑 }; onMounted(() => { // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 const handlers: GestureHandlers = { onScroll: handleScroll, // 轻扫 }; const configs: PointerOptions = { enableScroll: true, }; if (testDom.value) { instance.value = PointerGestureManager(testDom.value, handlers, configs); } }); onUnmounted(() => { // destroy销毁实例,实例销毁以后交互归一事件不再触发 if (instance.value) { instance.value.destroy(); } }); </script> <style scoped> #testId { width: 100%; height: 900px; background-color: aquamarine; } </style>
8、缩放事件
- RN适配指导
1. 主要方法和属性
Gesture.Pinch():手势缩放对象。
minDistance:number类型属性,触发缩放手势所需的最小距离。
minPointers:number类型属性,触发缩放手势需要的手指数目。
onStart:回调方法,手势缩放开始时的回调。
onUpdate:回调方法,手势缩放变化时的回调。
onCancel:回调方法,手势缩放取消时的回调。
onEnd:回调方法,手势缩放结束时的回调。
2. 示例
import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; //给需要的缩放的图片绑定手势组件 <GestureDetector gesture={pinchGesture}> <Animated.Image style={[styles.imageArtworkBig, animatedStyle]} source={require('../../../../asset/artwork.png')} resizeMode="contain" /> </GestureDetector> let scale = useSharedValue(0.9); const savedScale = useSharedValue(0.9); const pinchGesture = Gesture.Pinch() .onStart(e => { // 处理缩放开始时的回调事件 }) .onUpdate(e => { // 处理缩放过程中的回调事件 }) .onEnd(() => { // 处理缩放结束时的回调事件 });
- Flutter适配指导
1. 主要方法
Transform:包裹需要缩放的控件,利用scale属性改变来控制控件的缩放比例。
onPinchStart:缩放开始。
onPinchUpdate:缩放中,获取缩放比例event.scale,获取的比例较大,可以根据需求适当调整缩放比例,示例中是判断放大还是缩小的行为,从而控制控件固定比例放大和缩小。
onPinchEnd:缩放结束。
2. 回调参数
event.scale:缩放比例,用于PinchGesture手势触发场景,取值范围[0, +∞)。
3. 示例
UnifiedGestureDetector( pointerOptions: const PointerOptions( enablePinch: true, ), onPinchStart: onPinchStart, onPinchUpdate: onPinchUpdate, onPinchEnd: onPinchEnd, child: Transform( alignment: Alignment.center, transform: Matrix4.identity() ..translate(_offset.dx, _offset.dy) ..rotateZ(_rotation) ..scale(_scale), child: //需要缩放的widget ), ); void onPinchStart(GestureEvent event) {} void onPinchUpdate(GestureEvent event) { if (event.scale! < 0) { setState(() { // 缩小效果:图片的scale-0.005,通过Transform的scale属性实现缩小 }); } else if (event.scale! > 0) { setState(() { // 放大效果:图片的scale+0.005,通过Transform的scale属性实现放大 }); } // 限制缩放范围:防止widget缩放太小或者太大,体验不好 _scale = _scale.clamp(0.3, 1.0); } void onPinchEnd(GestureEvent event) {}
- H5适配指导
1. 主要方法
onPinchStart:缩放开始事件,在执行这个事件会默认禁止旋转事件。
onPinchMove:缩放中事件,通过event.scale缩放比例判断是放大还是缩小。
onPinchEnd:缩放结束事件,默认放开旋转事件。
2. 示例
<template> <div id="testId" ref="testDom"></div> </template> <script lang="ts" setup> import { onMounted, onUnmounted, ref } from "vue"; import { PointerGestureManager, PointerOptions, GestureHandlers, PointerState, } from "@hadss/web_uni_input"; const testDom = ref<HTMLElement | null>(null); const instance = ref(null); const handlePinchStart = (state: PointerState) => { // 代码编辑 }; const handlePinchMove = (state: PointerState) => { // 代码编辑 }; const handlePinchEnd = (state: PointerState) => { // 代码编辑 }; onMounted(() => { // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 const handlers: GestureHandlers = { onPinchStart: handlePinchStart, // 缩放开始 onPinchMove: handlePinchMove, // 缩放中 onPinchEnd: handlePinchEnd, // 缩放结束 }; const configs: PointerOptions = { enableScale: true, }; if (testDom.value) { instance.value = PointerGestureManager(testDom.value, handlers, configs); } }); onUnmounted(() => { // destroy销毁实例,实例销毁以后交互归一事件不再触发 if (instance.value) { instance.value.destroy(); } }); </script> <style scoped> #testId { width: 100%; height: 900px; background-color: aquamarine; } </style>
9、旋转事件
- RN适配指导
1. 主要方法和属性
Gesture.Rotation():手势旋转对象。
minAngle:number类型属性,触发旋转手势所需达到的最小角度。
minPointers:number类型属性,触发旋转手势需要的手指数目。
onStart:回调方法,手势旋转开始时的回调。
onUpdate:回调方法,手势旋转变化时的回调。
onCancel:回调方法,手势旋转取消时的回调。
onEnd:回调方法,手势旋转结束时的回调。
2. 示例
import { GestureDetector, Gesture} from '@hadss/react-native-uniinput'; //给需要旋转的的图片绑定手势组件 <GestureDetector gesture={rotationGestureForBackGround}> <Animated.Image style={[styles.imageArtworkBig, animatedStyle]} source={require('../../../../asset/artwork.png')} resizeMode="contain" /> </GestureDetector> const rotation = useSharedValue(0); const savedRotation = useSharedValue(0); // 创建旋转手势 const rotationGestureForBackGround = Gesture.Rotation() .onStart(() => { // 处理旋转开始时的回调事件 }) .onUpdate(e => { // 处理旋转过程中的回调事件 }) .onEnd(() => { // 处理旋转结束后的回调事件 });
- Flutter适配指导
1. 主要方法
Transform:包裹需要旋转的控件,利用rotateZ属性改变来控制控件的旋转角度。
onRotateStart:旋转开始。
onRotateUpdate:旋转中,获取旋转角度event.angle。
onRotateEnd:旋转结束。
2. 回调参数
event.angle:RotationGesture手势触发场景时,表示旋转角度,顺时针旋转为0度到180度,逆时针旋转为-180度到0度。
3. 示例
UnifiedGestureDetector( pointerOptions: const PointerOptions( enableRotate: true, ), onRotateStart: onRotateStart, onRotateUpdate: onRotateUpdate, onRotateEnd: onRotateEnd, child: Transform( alignment: Alignment.center, transform: Matrix4.identity() ..translate(_offset.dx, _offset.dy) ..rotateZ(_rotation) ..scale(_scale), child: //需要旋转的widget ), ); void onRotateStart(GestureEvent event) {} void onRotateUpdate(GestureEvent event) { setState(() { //赋值_ratation,通过Transform的rotateZ属性实现widget的旋转功能 _rotation = event.angle!; }); } void onRotateEnd(GestureEvent event) {}
- H5适配指导
1. 主要方法
onRotateStart:旋转开始事件,在执行这个事件会默认禁止缩放事件。
onRotateMove:缩放中事件,通过event.angle旋转角度判断是正向旋转还是逆向旋转。
onRotateEnd:旋转结束事件,默认放开缩放事件。
2. 示例
<template> <div id="testId" ref="testDom"></div> </template> <script lang="ts" setup> import { onMounted, onUnmounted, ref } from "vue"; import { PointerGestureManager, PointerOptions, GestureHandlers, PointerState, } from "@hadss/web_uni_input"; const testDom = ref<HTMLElement | null>(null); const instance = ref(null); const handleRotateStart = (state: PointerState) => { // 代码编辑 }; const handleRotateMove = (state: PointerState) => { // 代码编辑 }; const handleRotateEnd = (state: PointerState) => { // 代码编辑 }; onMounted(() => { // 如果要获取DOM元素,请在DOM元素挂载之后获取,比如VUE3生命周期的onMounted中获取DOM元素 const handlers: GestureHandlers = { onRotateStart: handleRotateStart, // 旋转开始 onRotateMove: handleRotateMove, // 旋转中 onRotateEnd: handleRotateEnd, // 旋转结束 }; const configs: PointerOptions = { enableRotate: true, }; if (testDom.value) { instance.value = PointerGestureManager(testDom.value, handlers, configs); } }); onUnmounted(() => { // destroy销毁实例,实例销毁以后交互归一事件不再触发 if (instance.value) { instance.value.destroy(); } }); </script> <style scoped> #testId { width: 100%; height: 900px; background-color: aquamarine; } </style>
按键事件适配
RN按键适配
ViewWithKeyEvent :按键组件。
onKeyEvent:触发按键事件时的回调。
eventType:对象属性,按键类型,值:unknown、up、down。
keyCode:按键的键码。
keyValue:按键的键值。
keySourceType:按键输入设备类型,值:unknown、mouse、keyboard、joystick。
import { ViewWithKeyEvent } from '@hadss/react-native-uniinput';
// ViewWithKeyEvent 组件包裹按键元素
<ViewWithKeyEvent onKeyEvent={downKeyEvent}>
<View>
<Text>按键</Text>
<View>
</ViewWithKeyEvent>
const downKeyEvent = event => {
if (!event || !event.nativeEvent || event.nativeEvent.eventType !== 'up') {
// 按键有按下、抬起两种事件类型,此处取类型为抬起的手势做处理。
return;
}
const keyValue = event.nativeEvent.keyValue || '';
console.log('event:', event.nativeEvent);
switch (keyValue) {
case 'KEYCODE_DPAD_UP':
//上键:切换歌曲为上一曲
skipToPrevious();
break;
case 'KEYCODE_DPAD_DOWN':
//下键:切换歌曲为下一曲
skipToNext();
break;
case 'KEYCODE_DPAD_LEFT':
//左键:控制播放器快退5s播放
if (position - 5 >= 0) {
setPosition(position - 5);
seekTo(position - 5);
} else {
setPosition(0);
seekTo(0);
}
break;
case 'KEYCODE_DPAD_RIGHT':
//右键:控制播放器快进5s播放
if (position + 5 <= duration) {
setPosition(position + 5);
seekTo(position + 5);
} else {
setPosition(duration);
seekTo(duration);
}
break;
case 'KEYCODE_ENTER':
//enter:当歌曲暂停状态时,按下enter键歌曲开始播放
togglePlayPause();
break;
case 'KEYCODE_ESCAPE':
//esc:回到上一级页面
changePageShow(true);
break;
default:
break;
}
};
Flutter按键适配
通过RawKeyboardListener监听键盘行为。
RawKeyboardListener(
focusNode: FocusNode(debugLabel: 'global_raw_keyboard'), // 确保焦点节点存在且可用
onKey: (RawKeyEvent event) {
if (event is RawKeyDownEvent) {
if (event.logicalKey == LogicalKeyboardKey.escape) {
//esc:回到上一级页面
Navigator.pop(context);
} else if (event.logicalKey == LogicalKeyboardKey.space) {
//空格:当歌曲播放状态时,按下空格键歌曲暂停
}else if (event.logicalKey == LogicalKeyboardKey.enter) {
//enter:当歌曲暂停状态时,按下enter键歌曲开始播放
}else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
//上键:切换歌曲为上一首
}else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
//下键:切换歌曲为下一首
}else if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
//左键:控制播放器快退5s播放
}else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
//右键:控制播放器快进5s播放
}
}
},
child: Container(...) //此处是需要监控的主页面widget;
)
H5按键适配
通过document.addEventListener('keyup', (event) => { })监听键盘行为。
document.addEventListener("keyup", (event) => {
switch (event.key) {
case "ArrowUp":
//上键:切换歌曲为上一曲
break;
case "ArrowDown":
//下键:切换歌曲为下一曲
break;
case "ArrowLeft":
//左键:控制播放器快退5s播放
break;
case "ArrowRight":
//右键:控制播放器快进5s播放
break;
case "Enter":
//enter:当歌曲暂停状态时,按下enter键歌曲开始播放
break;
case "Escape":
//esc:回到上一级页面
break;
case " ":
//空格:当歌曲播放状态时,按下空格键歌曲暂停
break;
}
})
组件及sample地址
RN:rn_multidevice_layout_scenepkg,Flutter:flutter_multidevice_layout_scenepkg,H5:web_adaptive_ui。
更多推荐
所有评论(0)