React Native横向ScrollView无法滚动问题求助
横向ScrollView无法滚动的解决方案
问题原因
你的代码里有两个关键问题导致横向ScrollView无法滚动:
- 分类按钮(
categoriesBtn/categoriesBtnActive)设置了flex:1,在横向ScrollView中,这个属性会让每个按钮均分ScrollView的可用宽度,所有按钮被压缩到可视区域内,没有超出内容,自然无法触发滚动。 SafeAreaView设置了flex:1,但父容器container已经固定了height:130,可能导致ScrollView的高度被挤压,进一步影响滚动交互。
修复步骤
- 移除按钮的flex:1属性:让按钮根据自身内容自适应宽度,这样多个按钮排列后会超出可视区域,触发滚动。
- 调整SafeAreaView的样式:去掉
flex:1,避免影响固定高度的容器布局。 - 优化按钮间距:在
scrollViewContent中添加gap属性,统一控制按钮之间的间距,代替每个按钮的paddingHorizontal,布局更整洁。
修改后的完整代码
import React, { useRef, useState } from 'react'; import { View, Text, SafeAreaView, StyleSheet, ScrollView, TouchableOpacity } from 'react-native'; import Colors from '@/constants/Colors'; import { Ionicons, MaterialIcons } from '@expo/vector-icons'; import * as Haptics from 'expo-haptics'; import { Link } from 'expo-router'; const categories = [ { name: 'Tiny homes', icon: 'home' }, { name: 'Cabins', icon: 'house-siding' }, { name: 'Trending', icon: 'local-fire-department' }, { name: 'Play', icon: 'videogame-asset' }, { name: 'City', icon: 'apartment' }, { name: 'Beachfront', icon: 'beach-access' }, { name: 'Countryside', icon: 'nature-people' }, ]; interface Props { onCategoryChanged: (category: string) => void; } const ExploreHeader = ({ onCategoryChanged }: Props) => { const scrollRef = useRef<ScrollView>(null); const itemsRef = useRef<Array<TouchableOpacity | null>>([]); const [activeIndex, setActiveIndex] = useState(0); const selectCategory = (index: number) => { const selected = itemsRef.current[index]; setActiveIndex(index); selected?.measure((x) => { scrollRef.current?.scrollTo({ x: x - 16, y: 0, animated: true }); }); Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); onCategoryChanged(categories[index].name); }; return ( <SafeAreaView style={{ backgroundColor: '#fff' }}> <View style={styles.container}> <View style={styles.actionRow}> <Link href={'/(modals)/booking'} asChild> <TouchableOpacity> <View style={styles.searchBtn}> <Ionicons name="search" size={24} /> <View> <Text style={{ fontFamily: 'mon-sb' }}>Where to?</Text> <Text style={{ color: Colors.grey, fontFamily: 'mon' }}>Anywhere · Any week</Text> </View> </View> </TouchableOpacity> </Link> <TouchableOpacity style={styles.filterBtn}> <Ionicons name="options-outline" size={24} /> </TouchableOpacity> </View> <ScrollView horizontal ref={scrollRef} showsHorizontalScrollIndicator={false} contentContainerStyle={styles.scrollViewContent}> {categories.map((item, index) => ( <TouchableOpacity ref={(el) => (itemsRef.current[index] = el)} key={index} style={activeIndex === index ? styles.categoriesBtnActive : styles.categoriesBtn} onPress={() => selectCategory(index)}> <MaterialIcons name={item.icon as any} size={24} color={activeIndex === index ? '#000' : Colors.grey} /> <Text style={activeIndex === index ? styles.categoryTextActive : styles.categoryText}> {item.name} </Text> </TouchableOpacity> ))} </ScrollView> </View> </SafeAreaView> ); }; const styles = StyleSheet.create({ container: { backgroundColor: '#fff', height: 130, elevation: 2, shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 6, shadowOffset: { width: 1, height: 10, }, }, actionRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: 24, paddingBottom: 16, }, searchBtn: { backgroundColor: '#fff', flexDirection: 'row', gap: 10, padding: 14, alignItems: 'center', width: 280, borderWidth: StyleSheet.hairlineWidth, borderColor: '#c2c2c2', borderRadius: 30, elevation: 2, shadowColor: '#000', shadowOpacity: 0.12, shadowRadius: 8, shadowOffset: { width: 1, height: 1, }, }, filterBtn: { padding: 10, borderWidth: 1, borderColor: '#A2A0A2', borderRadius: 24, }, categoryText: { fontSize: 14, fontFamily: 'mon-sb', color: Colors.grey, }, categoryTextActive: { fontSize: 14, fontFamily: 'mon-sb', color: '#000', }, categoriesBtn: { alignItems: 'center', justifyContent: 'center', paddingBottom: 8, paddingHorizontal: 16, }, categoriesBtnActive: { alignItems: 'center', justifyContent: 'center', borderBottomColor: '#000', borderBottomWidth: 2, paddingBottom: 8, paddingHorizontal: 16, }, scrollViewContent: { alignItems: 'center', paddingHorizontal:16, gap: 12, }, }); export default ExploreHeader;
额外说明
- 移除
flex:1后,按钮会根据文字和图标的宽度自适应,多个按钮排列后超出ScrollView的可视宽度,就能正常触发横向滚动。 - 如果滚动依然不生效,可以检查
container的height是否足够,确保ScrollView有足够的显示空间;也可以给ScrollView显式设置height属性(比如height: 60)来测试。
内容的提问来源于stack exchange,提问作者Adhayan Sharma
相关产品推荐
相关产品推荐

