Skip to content

交互与事件

React Native 核心基础

在 React Native 应用中,交互与事件处理是构建用户界面的重要部分。本文将详细介绍 React Native 中的各种事件类型和处理方法。

1. 点击事件

TouchableOpacity

TouchableOpacity 是最常用的触摸组件,它会在触摸时降低透明度,提供视觉反馈。

jsx
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

export default function TouchableOpacityExample() {
  const handlePress = () => {
    console.log('Button pressed!');
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        style={styles.button}
        onPress={handlePress}
        activeOpacity={0.7}
      >
        <Text style={styles.buttonText}>点击我</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#4CAF50',
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 5,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
  },
});

TouchableHighlight

TouchableHighlight 在触摸时会显示一个高亮效果。

jsx
import React from 'react';
import { View, Text, TouchableHighlight, StyleSheet } from 'react-native';

export default function TouchableHighlightExample() {
  const handlePress = () => {
    console.log('Button pressed!');
  };

  return (
    <View style={styles.container}>
      <TouchableHighlight
        style={styles.button}
        onPress={handlePress}
        activeOpacity={0.8}
        underlayColor="#388E3C"
      >
        <Text style={styles.buttonText}>点击我</Text>
      </TouchableHighlight>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#4CAF50',
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 5,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
  },
});

TouchableWithoutFeedback

TouchableWithoutFeedback 不提供任何视觉反馈,但可以捕获触摸事件。

jsx
import React from 'react';
import { View, Text, TouchableWithoutFeedback, StyleSheet } from 'react-native';

export default function TouchableWithoutFeedbackExample() {
  const handlePress = () => {
    console.log('Button pressed!');
  };

  return (
    <View style={styles.container}>
      <TouchableWithoutFeedback onPress={handlePress}>
        <View style={styles.button}>
          <Text style={styles.buttonText}>点击我</Text>
        </View>
      </TouchableWithoutFeedback>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#4CAF50',
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 5,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
  },
});

2. 长按事件

可以使用 onLongPress 属性来处理长按事件。

jsx
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet, Alert } from 'react-native';

export default function LongPressExample() {
  const handleLongPress = () => {
    Alert.alert('长按', '你长按了按钮!');
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity
        style={styles.button}
        onLongPress={handleLongPress}
        activeOpacity={0.7}
      >
        <Text style={styles.buttonText}>长按我</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    backgroundColor: '#2196F3',
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 5,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
  },
});

3. 滑动事件

PanResponder

PanResponder 可以处理复杂的手势交互,如滑动、拖动等。

jsx
import React, { useRef, useState } from 'react';
import { View, Text, StyleSheet, PanResponder, Animated } from 'react-native';

export default function PanResponderExample() {
  const pan = useRef(new Animated.ValueXY()).current;
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const panResponder = useRef(
    PanResponder.create({
      onMoveShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event(
        [null, { dx: pan.x, dy: pan.y }],
        { useNativeDriver: false }
      ),
      onPanResponderRelease: (e, gestureState) => {
        setPosition({
          x: position.x + gestureState.dx,
          y: position.y + gestureState.dy,
        });
        Animated.spring(pan, {
          toValue: { x: 0, y: 0 },
          useNativeDriver: false,
        }).start();
      },
    })
  ).current;

  return (
    <View style={styles.container}>
      <Text style={styles.title}>拖动方块</Text>
      <Animated.View
        style={[
          styles.box,
          {
            transform: [
              { translateX: pan.x },
              { translateY: pan.y },
              { translateX: position.x },
              { translateY: position.y },
            ],
          },
        ]}
        {...panResponder.panHandlers}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
    fontSize: 18,
    marginBottom: 20,
  },
  box: {
    width: 100,
    height: 100,
    backgroundColor: '#4CAF50',
    borderRadius: 5,
  },
});

ScrollView

ScrollView 可以处理滚动事件。

jsx
import React, { useState } from 'react';
import { View, Text, ScrollView, StyleSheet } from 'react-native';

export default function ScrollViewExample() {
  const [scrollY, setScrollY] = useState(0);

  const handleScroll = (event) => {
    setScrollY(event.nativeEvent.contentOffset.y);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.scrollInfo}>滚动位置: {scrollY.toFixed(0)}</Text>
      <ScrollView
        style={styles.scrollView}
        onScroll={handleScroll}
        scrollEventThrottle={16}
      >
        {Array.from({ length: 50 }).map((_, index) => (
          <View key={index} style={styles.item}>
            <Text style={styles.itemText}>项目 {index + 1}</Text>
          </View>
        ))}
      </ScrollView>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  scrollInfo: {
    padding: 10,
    backgroundColor: '#f0f0f0',
    fontSize: 16,
  },
  scrollView: {
    flex: 1,
  },
  item: {
    padding: 20,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
  },
  itemText: {
    fontSize: 16,
  },
});

4. 其他事件

文本输入事件

jsx
import React, { useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';

export default function TextInputExample() {
  const [text, setText] = useState('');

  const handleChangeText = (value) => {
    setText(value);
  };

  const handleSubmitEditing = () => {
    console.log('提交:', text);
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        value={text}
        onChangeText={handleChangeText}
        onSubmitEditing={handleSubmitEditing}
        placeholder="请输入文本"
        returnKeyType="done"
      />
      <Text style={styles.text}>输入: {text}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    borderRadius: 5,
    marginBottom: 20,
  },
  text: {
    fontSize: 16,
  },
});

焦点事件

jsx
import React, { useState } from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';

export default function FocusExample() {
  const [isFocused, setIsFocused] = useState(false);

  const handleFocus = () => {
    setIsFocused(true);
  };

  const handleBlur = () => {
    setIsFocused(false);
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={[styles.input, isFocused && styles.inputFocused]}
        onFocus={handleFocus}
        onBlur={handleBlur}
        placeholder="请输入文本"
      />
      <Text style={styles.status}>
        状态: {isFocused ? '获取焦点' : '失去焦点'}
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  input: {
    borderWidth: 1,
    borderColor: '#ddd',
    padding: 10,
    borderRadius: 5,
    marginBottom: 20,
  },
  inputFocused: {
    borderColor: '#4CAF50',
    borderWidth: 2,
  },
  status: {
    fontSize: 16,
  },
});

5. 事件处理最佳实践

1. 使用 useCallback 优化事件处理函数

jsx
import React, { useState, useCallback } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

export default function UseCallbackExample() {
  const [count, setCount] = useState(0);

  const handleIncrement = useCallback(() => {
    setCount(prevCount => prevCount + 1);
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.count}>{count}</Text>
      <TouchableOpacity
        style={styles.button}
        onPress={handleIncrement}
      >
        <Text style={styles.buttonText}>增加</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  count: {
    fontSize: 24,
    marginBottom: 20,
  },
  button: {
    backgroundColor: '#4CAF50',
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 5,
  },
  buttonText: {
    color: '#fff',
    fontSize: 16,
  },
});

2. 事件冒泡和阻止默认行为

在 React Native 中,事件不会自动冒泡,但你可以通过手动调用父组件的事件处理函数来实现类似的效果。

jsx
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

export default function EventBubblingExample() {
  const handleParentPress = () => {
    console.log('父组件被点击');
  };

  const handleChildPress = () => {
    console.log('子组件被点击');
    // 如果你想阻止父组件的事件,可以不调用 handleParentPress
  };

  return (
    <TouchableOpacity
      style={styles.parent}
      onPress={handleParentPress}
    >
      <Text style={styles.parentText}>父组件</Text>
      <TouchableOpacity
        style={styles.child}
        onPress={handleChildPress}
      >
        <Text style={styles.childText}>子组件</Text>
      </TouchableOpacity>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  parent: {
    padding: 20,
    backgroundColor: '#f0f0f0',
    borderRadius: 5,
  },
  parentText: {
    fontSize: 16,
    marginBottom: 10,
  },
  child: {
    padding: 10,
    backgroundColor: '#4CAF50',
    borderRadius: 5,
  },
  childText: {
    color: '#fff',
    fontSize: 14,
  },
});

3. 传递参数给事件处理函数

jsx
import React, { useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';

export default function PassingParamsExample() {
  const [selectedItem, setSelectedItem] = useState(null);

  const handleItemPress = (itemId) => {
    setSelectedItem(itemId);
    console.log('选中的项目:', itemId);
  };

  return (
    <View style={styles.container}>
      {Array.from({ length: 5 }).map((_, index) => (
        <TouchableOpacity
          key={index}
          style={[
            styles.item,
            selectedItem === index && styles.itemSelected
          ]}
          onPress={() => handleItemPress(index)}
        >
          <Text style={styles.itemText}>项目 {index + 1}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  item: {
    padding: 15,
    borderWidth: 1,
    borderColor: '#ddd',
    borderRadius: 5,
    marginBottom: 10,
  },
  itemSelected: {
    backgroundColor: '#E8F5E9',
    borderColor: '#4CAF50',
  },
  itemText: {
    fontSize: 16,
  },
});

6. 常见问题与解决方案

问题 1:触摸事件不响应

问题:触摸组件没有响应点击事件。

解决方案

  • 确保组件没有被其他组件遮挡
  • 检查 activeOpacity 属性是否设置正确
  • 确保事件处理函数没有语法错误
  • 检查组件是否设置了 disabled 属性

问题 2:滚动视图不滚动

问题:ScrollView 无法滚动。

解决方案

  • 确保 ScrollView 有足够的内容需要滚动
  • 检查 ScrollView 的 contentContainerStyle 是否设置了固定高度
  • 确保 ScrollView 没有被设置为 scrollEnabled={false}

问题 3:手势冲突

问题:多个手势组件之间存在冲突。

解决方案

  • 使用 PanResponderonMoveShouldSetPanResponder 方法来控制手势的优先级
  • 合理嵌套手势组件
  • 考虑使用第三方手势库如 react-native-gesture-handler

7. 总结

交互与事件处理是 React Native 应用开发的核心部分。通过本文的学习,你应该掌握了以下内容:

  1. 不同类型的触摸组件(TouchableOpacity, TouchableHighlight, TouchableWithoutFeedback)
  2. 点击事件和长按事件的处理
  3. 滑动事件和手势处理(PanResponder)
  4. 文本输入事件和焦点事件
  5. 事件处理的最佳实践
  6. 常见问题的解决方案

在实际开发中,合理使用这些事件处理方法,可以创建出更加交互性强、用户体验良好的应用。

© 2026 编程马·菜鸟教程 版权所有