拖动手指时取消按钮单击

问题描述

目标

用户的手指移开自定义按钮的onResponderRelease()时,取消该按钮。有没有在网上找不到的标准方法

我尝试过的事情

使用onLayout获取组件的位置,并使用onResponderMove的{​​{1}}的pageX / pageY来计算单击区域。但是,onLayout仅获得相对于父级的位置,因此不适用于模态。

GestureResponderEvent

其他想法

我还考虑过使用 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

解决方法

以下列方式使用measure()似乎对我有用。

  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

最后我得到了一个简单的钩子,只需将其放置在组件的引用上

const useMeasurement = (buffer = 0) => {
  const ref = useRef<View | null>(null)
  const [dimensions,})

  /* 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,width,height,py) => {
        setDimensions({
          minX: px - buffer,maxX: px + width + buffer,minY: py - buffer,maxY: py + height + buffer,})
      })
    }
  },[ref.current])

  return { dimensions,setRef }
}