React Native检测长按结束

12

我的问题非常简单,我正在尝试检测 onLongPress 事件的结束,也就是当用户释放长按时。

我已经尝试了 TouchableWithoutFeedback 中的所有事件,但每次只会触发一个事件。

import React from 'react'

import {
 View,
 Text,
 Dimensions,
 CameraRoll
} from 'react-native'

import Camera from 'react-native-camera';

const { width, height } = Dimensions.get('window')
class ImageBrowser extends React.Component {
 static navigationOptions = {
  title: 'Unsplash Images',
 }

 state = {
  images: [],
  loading: true,
  page: 1,
  isRecording : false
 }

 takeVideo(){
  this._recordVideo.bind(this);
 }

 _recordVideo(){
  this.camera.capture({mode: Camera.constants.CaptureMode.video})
   .then((data) => {
    console.log(data);
   })
   .catch((err) => {
    console.log(err)
   })
 }

 _stopRecord(){
  this.camera.stopCapture();
 }

 render() {
  return (
   <View style={{flex: 1}}>
    <Camera
     ref={(cam) => {this.camera = cam;}}
     style={styles.preview}
     aspect={Camera.constants.Aspect.fill}
     type={Camera.constants.Type.front}
    >
     <Text style={styles.capture} onLongPress={this.takeVideo.bind(this)} onPress={this._stopRecord.bind(this)} onPressOut={this._stopRecord.bind(this)}>[CAPTURE]</Text>
    </Camera>
   </View>
  )
 }
}

const styles = {
 preview: {
  flex: 1,
  justifyContent: 'flex-end',
  alignItems: 'center',
  height: Dimensions.get('window').height,
  width: Dimensions.get('window').width
 },
 capture: {
  flex: 0,
  backgroundColor: '#fff',
  borderRadius: 5,
  color: '#000',
  padding: 10,
  margin: 40
 }
}

export default ImageBrowser


分享您的代码以检查功能。 - Arunkumar
@arunkumar 编辑过 - Ethrak
6个回答

15

这正是我在寻找的!谢谢。 - zarathustra

7
更好的解决方案是采用@yongqian_iOS的建议进行以下操作:
<TouchableOpacity
   onPressOut={ () => console.warn('ENDED') }
   onLongPress={ () => console.warn('STARTED LONG PRESS') } 
/>

onPressIn 可用于长按操作。 - Savinder Singh
非常感谢,您的回答帮了我很多! - Vladimir Salguero

2
回答自己的问题。我最终使用了 手势响应器
onStartShouldSetResponder => 检测用户开始按下元素 onResponderRelease => 检测用户停止按下元素
以下是官方文档中使用PanResponder使视图摄入手势的示例:
class ExampleComponent extends Component {
    constructor(props) {
      super(props)
      this._panResponder = PanResponder.create({
        // Ask to be the responder:
        onStartShouldSetPanResponder: (evt, gestureState) => true,
        onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
        onMoveShouldSetPanResponder: (evt, gestureState) => true,
        onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,

        onPanResponderGrant: (evt, gestureState) => {
          // The gesture has started. Show visual feedback so the user knows
          // what is happening!

          // gestureState.d{x,y} will be set to zero now
        },
        onPanResponderMove: (evt, gestureState) => {
          // The most recent move distance is gestureState.move{X,Y}

          // The accumulated gesture distance since becoming responder is
          // gestureState.d{x,y}
        },
        onPanResponderTerminationRequest: (evt, gestureState) => true,
        onPanResponderRelease: (evt, gestureState) => {
          // The user has released all touches while this view is the
          // responder. This typically means a gesture has succeeded
        },
        onPanResponderTerminate: (evt, gestureState) => {
          // Another component has become the responder, so this gesture
          // should be cancelled
        },
        onShouldBlockNativeResponder: (evt, gestureState) => {
          // Returns whether this component should block native components from becoming the JS
          // responder. Returns true by default. Is currently only supported on android.
          return true;
        },
      });
    }

    render() {
      return (
        <View {...this._panResponder.panHandlers} />
      );
    }
  }

8
你能分享一段你的代码吗?看看你是如何解决这个问题的会很有帮助。 - ccostel

1
我不太确定我理解你的问题,但当我试图解决类似的问题时,它出现在我的Google搜索结果中。对于未来的读者,以下是我创建一个按钮的方法,该按钮在进入和退出时进行动画处理,但仅在未被取消(通过拖动手指或在父级ScrollView中滚动等)时触发操作。
import PropTypes from 'prop-types';
import React from 'react';
import { TouchableWithoutFeedback, Animated } from 'react-native';
// Vector Icons from here ♥‿♥: https://github.com/oblador/react-native-vector-icons
import { Feather } from '@expo/vector-icons';

export default class tomatoButt extends React.Component {
  static propTypes = {
    onPress: PropTypes.func.isRequired,
  };

  // No constructors needed! ┌(ㆆ㉨ㆆ)ʃ
  state = {
    animatedTouchScale: new Animated.Value(1),
  }

  animationStep = (toValue, callback, duration) => {
    const { animatedTouchScale } = this.state;
    Animated.timing(animatedTouchScale, {
      toValue,
      duration: duration || 100,
      useNativeDriver: true,
    }).start(callback);
  }

  // Scale the button down when the user "hovers" on it
  handlePressIn = () => this.animationStep(0.95);

  // Always scale out again, regardless if the touch is cancelled
  handlePressOut = () => this.animationStep(1);

  // If the user taps without holding, then animate in, trigger onPress, and animate out
  handlePress = () => {
    // onPress is an external function. Ex:
    // () => Alert.alert("Don't stop... (づ。◕‿‿◕。)づ")
    const { onPress } = this.props;
    this.animationStep(0.95, () => {
      onPress();
      this.animationStep(1, () => {}, 50);
    }, 50);
  }

  render() {
    return (
      <TouchableWithoutFeedback
         // Called first, when you first touch
        onPressIn={this.handlePressIn}
         // Called second, regardless if the touch is cancelled
        onPressOut={this.handlePressOut}
         // Called last, only when touch is released, but not if it's cancelled
        onPress={this.handlePress}
      >
        <Animated.View
          style={{
            // We'll scale the button down on touches:
            transform: [{ scale: animatedTouchScale }],
            // You should move these styles to an external sheet:
            backgroundColor: 'tomato',
            width: '100%',
            justifyContent: 'center',
            alignItems: 'center',
            borderRadius: 5,
            padding: 20,
            marginTop: 1,
            marginBottom: 1,
          }}
        >
          {/* Plus icon, OS independent */}
          <Feather
            name="plus"
            size={18}
            color="white"
          />
        </Animated.View>
      </TouchableWithoutFeedback>
    );
  }
}

1
使用onPressInonPressOut方法来捕获触摸事件的开始和结束。当用户触摸组件时,将调用onPressIn回调函数,而当用户释放触摸时,将触发onPressOut方法。请保留HTML标签。
<TouchableOpacity
   onPressIn={ () => console.warn('Touch started') }
   onPressOut={ () => console.warn('Touch ended') } 
/>

0
this.panResponder = PanResponder.create({
    onPanResponderRelease: (e, gestureState) => {
        Animated.timing(this.state.visible, {
            toValue: 0,
            duration: 200,
            useNativeDriver: true,
        }).start();
    },
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接