You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:14:54