react-native [Expo]:我可以增加 PanResponder 的输入采样率吗?
react-native [Expo]: can I increase PanResponder's input sampling rate?
我目前正在实施 react-native-svg based drawing input for my Expo application (it is a slight modification of this answer: )。我使用 PanResponder
来注册移动事件并创建不同的路径,然后当用户在视图上绘制时,我将这些路径显示为多个 Polyline
元素:
const GesturePath: React.FC<GesturePathProps> = ({
paths,
color,
width,
height,
strokeWidth,
}) => {
return (
<Svg height='100%' width='100%' viewBox={`0 0 ${width} ${height}`}>
{paths.map((path) => (
<Polyline
key={path.id}
points={path.points.map((p) => `${p.x},${p.y}`).join(" ")}
fill='none'
stroke={color}
strokeWidth={strokeWidth}
/>
))}
</Svg>
);
};
不幸的是,我制作的线条非常粗糙且参差不齐,我相信 PanResponder.onPanResponderMove
处理程序的触发频率太低,无法满足我的需要(在 Android Pixel 4 上平均每 50 毫秒调用一次模拟器,我不确定我是否可以从真实设备中得到更多。
也许在我的用例中有比 PanResponder 更好的处理手势的候选者?
我已经实现了一个平滑函数(基于这个答案 ),它的行为是正确的,但是由于点之间的距离太远,用户的输入会明显失真。
这是一个没有平滑的例子:
下面是我的 GestureHandler 实现:
const GestureRecorder: React.FC<GestureRecorderProps> = ({ addPath }) => {
const buffRef = useRef<Position[]>([]);
const pathRef = useRef<Position[]>([]);
const timeRef = useRef<number>(Date.now());
const pathIdRef = useRef<number>(0);
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderMove: (event) => {
// workaround for release event
// not working consistently on android
if (Date.now() - timeRef.current > RELEASE_TIME) {
pathIdRef.current += 1;
pathRef.current = [];
buffRef.current = [];
}
timeRef.current = Date.now();
pathRef.current.push({
x: event.nativeEvent.locationX,
y: event.nativeEvent.locationY,
});
addPath({
points: calculateSmoothedPath(event),
id: pathIdRef.current,
});
},
// not working on Android
// release event is not consistent
// onPanResponderRelease: () => {
// pathIdRef.current += 1;
// pathRef.current = [];
// buffRef.current = [];
// },
})
).current;
const calculateSmoothedPath = (event: GestureResponderEvent) => {
// implementation
// ...
// see:
}
return (
<View
style={StyleSheet.absoluteFill}
collapsable={false}
{...panResponder.panHandlers}
/>
);
};
旁注
我没有找到任何关于 PanResponder 的文档表明存在采样率配置选项,所以我完全接受替代方法(甚至完全放弃 PanResponder + 原生 SVG 方法),只要我不必弹出expo 项目,我可以控制布局(我不想使用特定 UI 附带的外部组件)。
我已经尝试使用 expo-pixi 库(特别是 Sketch
组件),但是存储库似乎不再被维护,并且在使用它时 expo 客户端一直崩溃。
在发布问题后我一直在尝试不同的解决方案,最后我稍微改变了我的 GestureHandler
实现。
我现在使用 react-native-gesture-handler 中的 PanGestureHandler
而不是 PanResponder
。
这个组件让用户指定一个 minDist
道具来调整激活,这里是来自文档的描述:
Minimum distance the finger (or multiple finger) need to travel before the handler activates. Expressed in points.
下面是新的实现:
<PanGestureHandler
minDist={1}
onGestureEvent={(e) => {
// same code from the previous onPanResponderMove
}
>
<View style={StyleSheet.absoluteFill} collapsable={false} />
</PanGestureHandler>
我也高估了我的 GPU 能力,而 运行 模拟器,在构建 APK 并在真实设备上测试后,我意识到绘图输入的行为更加流畅。
我目前正在实施 react-native-svg based drawing input for my Expo application (it is a slight modification of this answer: PanResponder
来注册移动事件并创建不同的路径,然后当用户在视图上绘制时,我将这些路径显示为多个 Polyline
元素:
const GesturePath: React.FC<GesturePathProps> = ({
paths,
color,
width,
height,
strokeWidth,
}) => {
return (
<Svg height='100%' width='100%' viewBox={`0 0 ${width} ${height}`}>
{paths.map((path) => (
<Polyline
key={path.id}
points={path.points.map((p) => `${p.x},${p.y}`).join(" ")}
fill='none'
stroke={color}
strokeWidth={strokeWidth}
/>
))}
</Svg>
);
};
不幸的是,我制作的线条非常粗糙且参差不齐,我相信 PanResponder.onPanResponderMove
处理程序的触发频率太低,无法满足我的需要(在 Android Pixel 4 上平均每 50 毫秒调用一次模拟器,我不确定我是否可以从真实设备中得到更多。
也许在我的用例中有比 PanResponder 更好的处理手势的候选者?
我已经实现了一个平滑函数(基于这个答案
这是一个没有平滑的例子:
下面是我的 GestureHandler 实现:
const GestureRecorder: React.FC<GestureRecorderProps> = ({ addPath }) => {
const buffRef = useRef<Position[]>([]);
const pathRef = useRef<Position[]>([]);
const timeRef = useRef<number>(Date.now());
const pathIdRef = useRef<number>(0);
const panResponder = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => true,
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderMove: (event) => {
// workaround for release event
// not working consistently on android
if (Date.now() - timeRef.current > RELEASE_TIME) {
pathIdRef.current += 1;
pathRef.current = [];
buffRef.current = [];
}
timeRef.current = Date.now();
pathRef.current.push({
x: event.nativeEvent.locationX,
y: event.nativeEvent.locationY,
});
addPath({
points: calculateSmoothedPath(event),
id: pathIdRef.current,
});
},
// not working on Android
// release event is not consistent
// onPanResponderRelease: () => {
// pathIdRef.current += 1;
// pathRef.current = [];
// buffRef.current = [];
// },
})
).current;
const calculateSmoothedPath = (event: GestureResponderEvent) => {
// implementation
// ...
// see:
}
return (
<View
style={StyleSheet.absoluteFill}
collapsable={false}
{...panResponder.panHandlers}
/>
);
};
旁注
我没有找到任何关于 PanResponder 的文档表明存在采样率配置选项,所以我完全接受替代方法(甚至完全放弃 PanResponder + 原生 SVG 方法),只要我不必弹出expo 项目,我可以控制布局(我不想使用特定 UI 附带的外部组件)。
我已经尝试使用 expo-pixi 库(特别是 Sketch
组件),但是存储库似乎不再被维护,并且在使用它时 expo 客户端一直崩溃。
在发布问题后我一直在尝试不同的解决方案,最后我稍微改变了我的 GestureHandler
实现。
我现在使用 react-native-gesture-handler 中的 PanGestureHandler
而不是 PanResponder
。
这个组件让用户指定一个 minDist
道具来调整激活,这里是来自文档的描述:
Minimum distance the finger (or multiple finger) need to travel before the handler activates. Expressed in points.
下面是新的实现:
<PanGestureHandler
minDist={1}
onGestureEvent={(e) => {
// same code from the previous onPanResponderMove
}
>
<View style={StyleSheet.absoluteFill} collapsable={false} />
</PanGestureHandler>
我也高估了我的 GPU 能力,而 运行 模拟器,在构建 APK 并在真实设备上测试后,我意识到绘图输入的行为更加流畅。