拖动手指时取消按钮单击 [英] Cancel button click when finger is dragged off

查看:81
本文介绍了拖动手指时取消按钮单击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户的手指从其上移开时,取消自定义按钮的 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆