拖动手指时取消按钮单击 [英] Cancel button click when finger is dragged off
问题描述
当用户的手指从其上移开时,取消自定义按钮的 onResponderRelease()
.有没有我无法在网上找到的标准方法?
Cancel custom button's onResponderRelease()
when the user's finger moves off of it. Is there a standard way of doing this that I'm not finding online?
使用 onLayout
来获取组件的位置,并使用 onResponderMove
的 GestureResponderEvent
的pageX/pageY来计算单击区域.但是,onLayout仅获得相对于父级的位置,因此不适用于模态.
Using onLayout
to grab the component's position and the onResponderMove
's GestureResponderEvent
's pageX/pageY to calculate the click area. However, onLayout only gets the position relative to the parent, so this doesn't work well with modals.
const handleMove = (e: GestureResponderEvent) => {
const { pageX, pageY } = e.nativeEvent
if (pageX < minX || pageX > maxX || pageY < minY || pageY > maxY) {
setCancelClick(true)
setLongPressed(false)
setPressed(false)
}
}
const setComponentDimensions = ({ nativeEvent }: LayoutChangeEvent) => {
const { x, y, width, height } = nativeEvent.layout
setMinX(x - BUFFER)
setMaxX(x + width + BUFFER)
setMinY(y - BUFFER)
setMaxY(y + height + BUFFER)
}
return (
<View
style={[style, pressed && pressedStyle]}
onStartShouldSetResponder={() => true}
onResponderGrant={() => setPressed(true)}
onResponderRelease={handleRelease}
onResponderMove={handleMove}
onLayout={setComponentDimensions}
onResponderTerminationRequest={() => false}
{...ViewProps}>
{children}
</View>
)
其他想法
我还考虑过使用 useRef
和裁判的 measure
.这可能有效.我正在使用的另一个库中的某个组件的引用中似乎没有 measure
,因此我担心的是这可能不是最灵活的解决方案.
Other thoughts
I have also considered using a useRef
and the ref's measure
. This might work. A component from another library that I'm using doesn't seem to have have measure
on its ref, so my concern is that this may not be the most flexible solution.
const viewRef = useRef(null as View | null)
useEffect(() => {
if (viewRef.current) {
// TODO: base calculations off of measure
console.log(viewRef.current.measure)
}
}, [viewRef.current])
...
return (
<View
ref={(view) => (viewRef.current = view)}
...
{children}
</View>
)
推荐答案
按以下方式使用 measure()
似乎对我有用.
Using measure()
in the following way seems to work for me.
const viewRef = useRef(null as View | null)
const [dimensions, setDimensions] = useState({
minX: 0,
maxX: 0,
minY: 0,
maxY: 0,
})
const handleMove = (e: GestureResponderEvent) => {
const { pageX, pageY } = e.nativeEvent
const { minX, maxX, minY, maxY } = dimensions
if (pageX < minX || pageX > maxX || pageY < minY || pageY > maxY) {
setLongPressed(false)
setPressed(false)
}
}
const setComponentDimensions = ({ nativeEvent }: LayoutChangeEvent) => {
const { width, height } = nativeEvent.layout
if (viewRef.current) {
viewRef.current.measure((_a, _b, _width, _height, px, py) => {
setDimensions({
minX: px - BUFFER,
maxX: px + width + BUFFER,
minY: py - BUFFER,
maxY: py + height + BUFFER,
})
})
}
}
return (
<View
ref={(view) => (viewRef.current = view)}
onStartShouldSetResponder={() => true}
onResponderMove={handleMove}
onLayout={setComponentDimensions}
onResponderTerminationRequest={() => false}
{children}
</View>
)
更新
在稍微重构了组件并且从未尝试过之后,我决定发布一个程序包.希望它可以对其他人有所帮助: react-native-better-buttons
最后我得到了一个简单的钩子,只需将其放置在组件的引用上
I ended up with a simpler hook that just needs to be put on the component's ref
const useMeasurement = (buffer = 0) => {
const ref = useRef<View | null>(null)
const [dimensions, setDimensions] = useState({
minX: 0,
maxX: 0,
minY: 0,
maxY: 0,
})
/* This goes on the view's ref property */
const setRef = (view: View) => (ref.current = view)
/*
Updating ref.current does not cause rerenders, which is fine for us.
We just want to check for ref.current updates when component that uses
us rerenders.
*/
useEffect(() => {
if (ref.current && ref.current.measure) {
ref.current.measure((_a, _b, width, height, px, py) => {
setDimensions({
minX: px - buffer,
maxX: px + width + buffer,
minY: py - buffer,
maxY: py + height + buffer,
})
})
}
}, [ref.current])
return { dimensions, setRef }
}
这篇关于拖动手指时取消按钮单击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!