Open liquidTM opened 2 years ago
最近项目中使用了Ant design中的SwipeAction组件做了个滑动删除的功能,ios正常,android设备无效 原因应该是android代码中没有把的ReactRootView添加进MainActivity.java中。代码如下: import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
最近项目中使用了Ant design中的SwipeAction组件做了个滑动删除的功能,ios正常,android设备无效
import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
@Override protected String getMainComponentName() { return "Example"; }
@Override protected ReactActivityDelegate createReactActivityDelegate() { return new ReactActivityDelegate(this, getMainComponentName()) { @Override protected ReactRootView createRootView() { return new RNGestureHandlerEnabledRootView(MainActivity.this); } };
} }
> ### 看SwipeAction源码,发现使用了react-native-gesture-handler的Swipable组件,借此机会了解下自己一直不明白的react-native-gesture-handler到底是干什么的。 ## 背景 说到 React Navtive 的性能优化,首先要了解 React Native 的运行机制。React Native 程序主要运行在三个并行的线程上: - JavaScript Thread:我们写的 JavaScript 代码逻辑都是在这个线程上执行; - UI Thread:即原生线程,当我们需要调用原生的渲染或者能力时会运行到这个线程上; - Shadow Thread:这个线程创建和管理着 Shadow Tree,它类似于虚拟 DOM 。它通过 Yoga 引擎将 Flexbox 布局转化为原生的布局方式。 这三个线程独立运行的情况下,性能良好,但如果涉及到事件驱动与 UI 线程有交互的情况,React Native 的这种设计效果不佳。 当与触摸屏交互时,用户希望屏幕上的效果是即时的。如果更新发生在单独的线程中,通常情况下,在JavaScript线程中所做的更改无法反映在同一帧中。在 React Native中,默认情况下,由于UI和JavaScript线程之间的通信是异步的,并且UI线程从不等待JavaScript线程完成处理事件,因此所有更新都会延迟至少一个帧。 而且由于UI线程与其他线程通信存在序列化和反序列化这个比较消耗性能的步骤,当UI线程与其他线程交互比较频繁或者其他线程负荷较大时,通常事件无法立即处理,从而造成更严重的延迟。 我们的RN代码逻辑都是用JavaScript写的,JavaScript线程也是负荷最大的线程。因此在React Native的性能优化上主要要考虑两个方面: 减少与UI线程的通信; 减少JavaScript线程的负荷; 而React Native Gesture Handler正是从这两个方面优化React Native在手势操作方面的性能。它旨在替换React Native自带的手势处理系统。如果你使用过系统自带的手势处理系统,会发现在JavaScript线程会有大量的计算,这些计算也会频繁与UI线程通信,对性能影响较大。具体代码对比如下: ![image](https://user-images.githubusercontent.com/20810764/161087459-bd8316e5-53f1-4739-9597-696e83f4ac18.png)### ## 功能 React Native Gesture Handler提供了以下功能: - 提供了包括缩放、旋转、屏蔽滑动等手势的处理系统; - 能够定义多个手势之间的关系。例如:当你在ScrollView里面加入一个滑动手势(pan handler)时,可以让滑动手势响应结束后再响应ScrollView; - 提供了让手势运行在原生线程(UI线程)上并遵从原生平台默认行为机制; - 由于使用了原生的动画驱动,即便在JavaScript线程已经超负荷的情况,也能够提供顺滑的手势交互。 ## 核心概念 ### Gesture Handlers > Gesture Handler是这个手势库的核心,它用来描述原生触控系统里的元素,这些元素能够被JavaScript代码使用React的组件进行实例化和控制。 > 每一个Handler类型都代表了一种手势(例如:滑动、缩放),也包含了每种手势特有的事件(例如:translation, scale)。 > 这些Handler可以在UI线程同步地解析触摸事件流,即便在JavaScript线程阻塞的情况下也能保证手势交互不被打断。 > ### Gesture Handler的组件并不会在原生的视图层级里面创建一个视图,它仅仅是在自己库里面注册然后连接到原生的视图里。所以当我们在使用这些Handler组件的时候,一定要记得在内部添加一个对应着原生视图的子组件。 这个库提供了以下几种手势: - PanGestureHandler - TapGestureHandler - LongPressGestureHandler - RotationGestureHandler - FlingGestureHandler - PinchGestureHandler - ForceTouchGestureHandler ### 手势分类 > 这个手势库将手势分为两种:连续的和非连续的。 > 连续的手势被激活后会持续一段较长的时间,它会产生一个手势事件流。例如像滑动手势(PanGestureHandler),它被激活后就会开始持续为translation和其他属性提供更新。 > 而非连续性的手势一旦被激活就会立即结束。长按手势(LongPressGestureHandler)就是一个非连续的手势,它只在手指按住持续一段时间后会被激活,并不会追踪手指的移动。 ### 记住只有连续的手势才能使用onGestureEvent,非连续性的手势Handler没有这个属性。 ### onGestureEvent > onGestureEvent参数接收Animated.event方法,这个方法是React Native系统自带的动画处理库的事件处理方法,例如:
const circleRadius = 30; class Circle extends Component { _touchX = new Animated.Value(windowWidth / 2 - circleRadius); _onPanGestureEvent = Animated.event([{ nativeEvent: { x: this._touchX } }], { useNativeDriver: true, }); render() { return (
);
> Animated.event会持续将nativeEvent里的x属性的值同步到对应的_touchX,而_touchX的改变会同步到Animated.View的translateX的改变,从而导致Animated.View的位移。上面就是一个简单的跟随手势移动的小球的例子。 > 这里其实也可以配合React Native Reanimated库使用,直接传入useAnimatedGestureHandler即可,在使用上也更简单。 ### Handler的嵌套 > Handler只是锚定了它的子组件,并没有在原生视图层级里创建新的视图,因此这些手势Handler并不支持直接嵌套,需要在两个手势Handler之间放入组件 > 另外一个特别需要注意的是当你在Animated.event中使用了useNativeDriver,它里面嵌套的子节点必须是Animated.API类型的。比例像View就必须被替换成Animated.View。 ### Handler State > 手势Handler可以被看作是一个状态机,每个Handler在有新的手势事件触发或者手势系统状态变更时都会更新当前的状态。 Handler的状态分为以下几种: - UNDETERMINED - FAILED - BEGAN - CANCELLED - ACTIVE - END 顾名思义,这里就不作过多解释了。 ### 获取状态 我们可以通过onHandlerStateChange来监听Handler的状态。状态可以通过nativeEvent的state属性获取到,然后与这个手势库中的State对象里的常量进行对比:
import { State, LongPressGestureHandler } from 'react-native-gesture-handler';
class Demo extends Component { _handleStateChange = ({ nativeEvent }) => { if (nativeEvent.state === State.ACTIVE) { Alert.alert('Longpress'); } }; render() { return (
Longpress me );
### 状态转换顺序 > 最典型的状态转换顺序就是手势Handler捕获到触摸事件,然后识别出具体的手势,手势结束后重置到最初状态。这种状态转换顺序如下所示(长箭头表示状态改变前这里可能有更多的触摸事件): - UNDETERMINED -> BEGAN ——> ACTIVE ——> END -> UNDETERMINED > 下面这种是Handler捕获到了触摸事件但是识别手势的时候失败的情况: - UNDETERMINED -> BEGAN ——> FAILED -> UNDETERMINED > 下面这种是手势中断的情况: - UNDETERMINED -> BEGAN ——> ACTIVE ——> CANCELLED -> UNDETERMINED ### 手势之间的交互 这个手势库支持不同的手势Handler之间通信来构建更加复杂的手势交互。 有下面两种方法可以实现这种交互控制。每一种方法手势Handler都需要提供一个引用给其他Handler。手势Handler的引用是通过React.createRef()来创建的引用对象。 ### 1. 同时识别 默认情况下同一个时间只有一种手势Handler可以是激活状态。当手势Handler识别到了一个手势,它会取消其他所有处于began状态的手势Handler并且在其激活状态下停止接收其他任何触摸事件。 这种行为可以通过simultaneousHandlers这个属性来改变,并且这个属性每种类型的Handler都有。这个属性持有一个数组,数组里有其他手势Handler的引用。手势Handler可以通过这种方式同时处于激活状态。 > 使用场景 > 当我们实现图片预览组件的时候就需要这种同时识别,在图片预览中我们可以缩放、旋转而且可以在它缩放时移动它。在这个场景中我们需要使用PinchGestureHandler, RotationGestureHandler和PanGestureHandler并让它们能够被同时识别。 > 示例:可以查看官方示例App中的”Scale, rotate & tilt” example部分。 ### 2. 等待其他手势完成 > 使用场景 > 这种手势交互方式最好的例子就是当我们在一个视图上同时注册了单次点击和双击事件的情况。这种情况下就需要单击事件等待双击事件识别完成后才识别,否则就会出现只识别单击事件而双击事件无法触发的情况。 > 示例:参考官方示例App中的”Multitap” example部分。 ## 总结 - React Native Gesture Handler的基本使用就介绍完了。关于React Native优化,本文介绍的手势库只是解决了手势方面的性能问题。 - 一般来说,手势都是配合了相应的动画使用的,比如手势拖拽功能,动画的性能优化库React Native Reanimated和手势库的配合使用效果更好。 ### 转载自: [react-native-gesture-handler的使用](https://www.lycecho.com/archives/12013)
大佬,你这java里的代码不太对吧
public class MainActivity extends ReactActivity {
@Override protected String getMainComponentName() { return "Example"; }
} }
const circleRadius = 30; class Circle extends Component { _touchX = new Animated.Value(windowWidth / 2 - circleRadius); _onPanGestureEvent = Animated.event([{ nativeEvent: { x: this._touchX } }], { useNativeDriver: true, }); render() { return (
} }
import { State, LongPressGestureHandler } from 'react-native-gesture-handler';
class Demo extends Component { _handleStateChange = ({ nativeEvent }) => { if (nativeEvent.state === State.ACTIVE) { Alert.alert('Longpress'); } }; render() { return (
} }