React Native Expo中ScrollView无法同时横竖滚动问题求助
问题描述
我有一个基于导航模板的React Native Expo应用,正在开发工位预约兴趣项目,用户可预订工位。我使用react-native-svg组件实现,创建了10个虚拟工位,设置Svg组件宽1200px、高1600px。目前ScrollView仅能横向滚动,无法纵向滚动;若将ScrollView改为View,则可纵向滚动但无法横向滚动。请问问题出在哪里?
相关代码
OfficeSvgBooking.tsx
import React, { useState } from "react"; import { StyleSheet, ScrollView } from "react-native"; import Svg, { Rect, Text } from "react-native-svg"; import { View } from "./Themed"; export default function OfficeSvgBooking() { const [selectedDesks, setSelectedDesks] = useState<string[]>([]); const toggleDesk = (deskId: string) => { setSelectedDesks((prev) => prev.includes(deskId) ? prev.filter((id) => id !== deskId) : [...prev, deskId] ); }; const desks = [ { id: "desk1", x: 50, y: 50, isRotated: false }, { id: "desk2", x: 150, y: 50, isRotated: true }, { id: "desk3", x: 250, y: 150, isRotated: false }, { id: "desk4", x: 350, y: 250, isRotated: true }, { id: "desk5", x: 450, y: 350, isRotated: false }, { id: "desk6", x: 550, y: 450, isRotated: true }, { id: "desk7", x: 650, y: 550, isRotated: false }, { id: "desk8", x: 750, y: 650, isRotated: true }, { id: "desk9", x: 850, y: 750, isRotated: false }, { id: "desk10", x: 950, y: 850, isRotated: true }, ]; return ( <ScrollView contentContainerStyle={styles.scrollContainer} style={styles.scrollView} horizontal={true} directionalLockEnabled={false} > <Svg height="1600" width="1200"> <Rect x="0" y="0" width="1200" height="1600" fill="lightgray" /> {desks.map((desk) => ( <React.Fragment key={desk.id}> <Rect x={desk.x} y={desk.y} width={desk.isRotated ? "80" : "40"} height={desk.isRotated ? "40" : "80"} fill={selectedDesks.includes(desk.id) ? "green" : "red"} onPress={() => toggleDesk(desk.id)} /> <Text x={desk.isRotated ? desk.x + 40 : desk.x + 20} y={desk.isRotated ? desk.y + 25 : desk.y + 45} fontSize="12" fill="white" textAnchor="middle" onPress={() => toggleDesk(desk.id)} > {desk.id} </Text> </React.Fragment> ))} </Svg> </ScrollView> ); } const styles = StyleSheet.create({ scrollView: { flex: 1, }, scrollContainer: { width: 1200, height: 1600, }, });
two.tsx
import { StyleSheet } from 'react-native'; import { View } from '@/components/Themed'; import OfficeSvgBooking from '@/components/thirdFloor'; export default function TabTwoScreen() { return ( <View style={styles.container}> <OfficeSvgBooking /> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, // alignItems: 'center', // justifyContent: 'center', }, });
问题原因及解决方案
原因
React Native的ScrollView默认仅支持单一方向滚动:
- 当设置
horizontal={true}时,ScrollView会锁定纵向滚动,只响应横向滑动操作; - 若不设置
horizontal(默认纵向),则只能响应纵向滚动,横向内容会被截断或无法滑动。
你的SVG尺寸(宽1200px、高1600px)远大于屏幕尺寸,需要同时支持横向和纵向滚动,但单个ScrollView无法实现双向滚动。
解决方案
通过嵌套ScrollView实现双向滚动:外层ScrollView处理纵向滚动,内层ScrollView处理横向滚动,将SVG放在内层ScrollView中。
修改后的OfficeSvgBooking.tsx代码如下:
import React, { useState } from "react"; import { StyleSheet, ScrollView } from "react-native"; import Svg, { Rect, Text } from "react-native-svg"; import { View } from "./Themed"; export default function OfficeSvgBooking() { const [selectedDesks, setSelectedDesks] = useState<string[]>([]); const toggleDesk = (deskId: string) => { setSelectedDesks((prev) => prev.includes(deskId) ? prev.filter((id) => id !== deskId) : [...prev, deskId] ); }; const desks = [ { id: "desk1", x: 50, y: 50, isRotated: false }, { id: "desk2", x: 150, y: 50, isRotated: true }, { id: "desk3", x: 250, y: 150, isRotated: false }, { id: "desk4", x: 350, y: 250, isRotated: true }, { id: "desk5", x: 450, y: 350, isRotated: false }, { id: "desk6", x: 550, y: 450, isRotated: true }, { id: "desk7", x: 650, y: 550, isRotated: false }, { id: "desk8", x: 750, y: 650, isRotated: true }, { id: "desk9", x: 850, y: 750, isRotated: false }, { id: "desk10", x: 950, y: 850, isRotated: true }, ]; return ( {/* 外层ScrollView:处理纵向滚动 */} <ScrollView style={styles.scrollView}> {/* 内层ScrollView:处理横向滚动 */} <ScrollView horizontal={true}> <Svg height="1600" width="1200"> <Rect x="0" y="0" width="1200" height="1600" fill="lightgray" /> {desks.map((desk) => ( <React.Fragment key={desk.id}> <Rect x={desk.x} y={desk.y} width={desk.isRotated ? "80" : "40"} height={desk.isRotated ? "40" : "80"} fill={selectedDesks.includes(desk.id) ? "green" : "red"} onPress={() => toggleDesk(desk.id)} /> <Text x={desk.isRotated ? desk.x + 40 : desk.x + 20} y={desk.isRotated ? desk.y + 25 : desk.y + 45} fontSize="12" fill="white" textAnchor="middle" onPress={() => toggleDesk(desk.id)} > {desk.id} </Text> </React.Fragment> ))} </Svg> </ScrollView> </ScrollView> ); } const styles = StyleSheet.create({ scrollView: { flex: 1, }, });
额外说明
- 移除了原
contentContainerStyle的固定宽高设置,因为内层ScrollView会自动根据SVG的尺寸调整内容容器大小; - 嵌套结构中,外层ScrollView默认纵向滚动,内层通过
horizontal={true}开启横向滚动,两者配合实现双向滑动; - 保持
directionalLockEnabled={false}(可选),允许用户同时触发横向和纵向滚动,但嵌套结构本身已能支持双向操作。
内容的提问来源于stack exchange,提问作者KnightBlood33
相关产品推荐
相关产品推荐

