ScrollView
- 支持固定子组件
- 支持列表
- 支持数组
// 固定子组件
<ScrollView style={styles.container}>
<Text style={styles.txt}>1</Text>
<Text style={styles.txt}>2</Text>
<Text style={styles.txt}>3</Text>
<Text style={styles.txt}>4</Text>
<Text style={styles.txt}>5</Text>
</ScrollView>
// 数组
<ScrollView style={styles.container}>
{arr.map((item, index) => {
return (
<Text key={index} style={styles.txt}>
{item}
</Text>
);
})}
</ScrollView>
// 列表
const buildListView = () => {
const arr1 = [];
for (let i = 0; i < 20; i++) {
arr1.push(<Text key={i} style={styles.txt}>{`List Item ${i + 1}`}</Text>);
}
return arr1;
};
<ScrollView style={styles.container}>
{buildListView()}
</ScrollView>
Props
contentContainerStyle
内容包裹样式,如设置列表内边距,样式同 View 组件
contentContainerStyle?: StyleProp<ViewStyle> | undefined;
contentContainerStyle 的样式将应用于滚动视图的内容容器,该容器包装了所有的子视图。示例:
return (
<ScrollView contentContainerStyle={styles.contentContainer}>
</ScrollView>
);
...
const styles = StyleSheet.create({
contentContainer: {
paddingVertical: 20
}
});
-
contentContainerStyle用来设置内容区域的样式,如 padding、alignItems、flexDirection 等,但 不能使用 margin -
如果需要设置组件外部的外边距,应该使用
style
keyboardDismissMode
确定在拖动操作中是否会隐藏键盘
keyboardDismissMode?: 'none' | 'interactive' | 'on-drag' | undefined;
-
'none'(默认值)拖动操作不会隐藏键盘
-
'onDrag' (Android)当开始拖动时,键盘会被隐藏
-
'interactive' (iOS)当用户进行滚动操作时,键盘会随着滚动动作进行交互式地隐藏,即键盘会在手指拖动的过程中与视图同步移动。如果用户向上拖动内容,键盘会逐渐消失;如果用户向下拖动,键盘会重新出现
keyboardShouldPersistTaps
用于控制在触摸事件发生时,键盘是否应该保持显示状态
-
'never' (默认值):点击 ScrollView 包裹的任何地方都会隐藏键盘。
-
'always' :点击任何地方都不会隐藏键盘,键盘将始终保持显示状态。
-
'handled' :只有在点击一个能够处理触摸事件的视图时(比如按钮或输入框)才会隐藏键盘,其他地方点击不会隐藏键盘。
使用场景:
- 当你希望用户点击页面上的其他区域(例如,点击按钮或其他内容)时,键盘不被自动关闭时,使用
keyboardShouldPersistTaps="handled"或keyboardShouldPersistTaps="always"是很有用的。 - 当用户在输入框之外的区域进行交互时,希望键盘仍然保持打开时,可以选择
always。 - 如果你想要更细致的控制,例如点击特定的区域(如按钮)才隐藏键盘,可以使用
handled。
点击事件处理:
- 'never'
- 当键盘弹出时,点击按钮(或者其他有触摸事件的组件)时,键盘会隐藏,触摸事件不会被触发
- 当键盘收起时,再点非触摸事件组件,则会触发触摸事件
<ScrollView keyboardShouldPersistTaps="never">
<TextInput />
<Button title="Click me" onPress={() => console.log("Button clicked")} />
</ScrollView>
- 'always'
- 点击事件会直接传递给子组件(例如按钮、文本框等),并且键盘保持可见状态。滚动组件本身不会响应点击事件,点击会被传递给子视图
- 即使键盘是弹出的,点击按钮(或者其他有触摸事件的组件)时,按钮的点击事件仍然会被触发,键盘不会消失
<ScrollView keyboardShouldPersistTaps="always">
<TextInput />
<Button title="Click me" onPress={() => console.log("Button clicked")} />
</ScrollView>
- 'handled'
- 点击按钮(或者其他有触摸事件的组件)时,键盘不会隐藏,按钮的点击事件会被触发。如果点击背景区域,键盘会隐藏
<ScrollView keyboardShouldPersistTaps="handled">
<TextInput />
<Button title="Click me" onPress={() => console.log("Button clicked")} />
</ScrollView>
总结对比:
PS:外部区域是指 ScrollView 包裹的任何地方,除了输入控件(当前聚焦的文本输入框)外的区域
| keyboardShouldPersistTaps | 键盘消失行为 | 点击事件处理 | 适用场景 |
|---|---|---|---|
'never' | 点击外部区域时,键盘隐藏 | 点击事件不传递给子视图 | 希望点击外部区域时隐藏键盘的场景 |
'always' | 键盘始终保持显示 | 点击事件传递给子视图 | 键盘始终显示,允许子视图处理点击事件 |
'handled' | 点击外部区域时,键盘隐藏 | 点击事件由子视图处理 | 点击子视图时键盘不消失,点击外部区域时消失 |
false | 与 'never' 相同 | 与 'never' 相同 | 已弃用,推荐使用 'never' |
true | 与 'always' 相同 | 与 'always' 相同 | 已弃用,推荐使用 'always' |
onMomentumScrollBegin
当滚动视图开始滚动时触发,且是松手的时候触发
onMomentumScrollBegin?:
| ((event: NativeSyntheticEvent<NativeScrollEvent>) => void)
| undefined;
onMomentumScrollEnd
当滚动视图停止滚动时触发
onMomentumScrollEnd?:
| ((event: NativeSyntheticEvent<NativeScrollEvent>) => void)
| undefined;
onScroll
是在滚动过程中每帧最多触发一次的事件,用于获取当前滚动的位置信息
其触发频率可以通过
scrollEventThrottle属性控制(仅 iOS)
/**
* 在滚动过程中每帧最多触发一次。
* 事件的触发频率可以通过 scrollEventThrottle 属性进行控制。
*/
onScroll?:
| ((event: NativeSyntheticEvent<NativeScrollEvent>) => void)
| undefined;
<ScrollView
onMomentumScrollBegin={() => {
console.log('onMomentumScrollBegin');
}}
onMomentumScrollEnd={() => {
console.log('onMomentumScrollEnd');
}}
onScroll={event => {
console.log(event.nativeEvent.contentOffset);
}}
>
<Text></Text>
...
</ScrollView>
horizontal
控制滚动方向是否水平方向滚动
/**
* 如果为 true,滚动视图的子元素将水平排列在一行中,而不是垂直排列在一列中。默认值为 false。
*/
horizontal?: boolean | null | undefined
pagingEnabled
用于控制滚动视图的分页行为
/**
* 如果为 true,滚动视图在滚动时会停在视图大小的倍数位置。这可以用于水平分页。默认值为 false。
*/
pagingEnabled?: boolean | undefined;
使用场景:
pagingEnabled为true时,滚动视图会在每次滚动时停在视图的大小倍数位置,类似于分页效果。这个特性常用于需要分页的场景,比如轮播图、分页滚动的内容等。- 默认值为
false,意味着滚动不会强制对齐到页面边界,用户可以自由地滚动。
<ScrollView
horizontal={true} // 水平滚动
pagingEnabled={true} // 启用分页效果
>
<View style={{ width: 300, height: 200, backgroundColor: 'red' }} />
<View style={{ width: 300, height: 200, backgroundColor: 'blue' }} />
<View style={{ width: 300, height: 200, backgroundColor: 'gray' }} />
</ScrollView>
在上面的示例中,pagingEnabled={true} 会使得滚动视图每次滚动时停在每个 View 组件的边界,每个 View 会作为一页显示。
scrollEnabled
控制滚动视图是否可以滚动
/**
* 如果为 false,内容不可滚动。默认值为 true。
*/
scrollEnabled?: boolean | undefined; // true
contentOffset
用于设置滚动视图的初始滚动位置,即内容从哪里开始显示
x: 水平偏移量,控制水平滚动的初始位置。y: 垂直偏移量,控制垂直滚动的初始位置。
/**
* 用于手动设置初始的滚动偏移量。
* 默认值是 {x: 0, y: 0}。
*/
contentOffset?: PointProp | undefined; // 默认值是 {x: 0, y: 0}
示例:
<ScrollView contentOffset={{ x: 100, y: 200 }}>
<Text>这里是滚动视图的内容</Text>
</ScrollView>
在上面的示例中,contentOffset={{ x: 100, y: 200 }} 会使得 ScrollView 在加载时,内容从水平 100 和垂直 200 的位置开始显示。
showsHorizontalScrollIndicator
控制是否显示水平滚动条,默认显示
/** * 如果为 true,显示水平滚动条。 */
showsHorizontalScrollIndicator?: boolean | undefined;
showsVerticalScrollIndicator
控制是否显示垂直滚动条,默认显示
/**
* 如果为 true,显示垂直滚动条。
*/
showsVerticalScrollIndicator?: boolean | undefined;
stickyHeaderIndices
用于指定哪些子元素在滚动时应固定在屏幕顶部,通常用于实现“粘性头部”效果(例如,固定的标题)。
/**
* 一个子元素索引的数组,决定哪些子元素在滚动时固定在屏幕顶部。
* 例如,传入 `stickyHeaderIndices={[0]}` 会使第一个子元素固定在滚动视图的顶部。
* 此属性不支持与 `horizontal={true}` 一起使用。
*/
stickyHeaderIndices?: number[] | undefined;
使用场景:
- 当你希望某些元素在滚动过程中始终保持在屏幕顶部时(如导航栏、标题等),可以使用此属性。
- 注意:此属性 不支持与
horizontal={true}一起使用,意味着只适用于垂直滚动视图。
API
import React, {useRef} from 'react';
const scrollRef = useRef(null);
scrollRef.current.scrollTo({y: 300, animation: true});
scrollRef.current.scrollToEnd();
FlatList
- 高效渲染:仅渲染可见项,提高性能,尤其在长列表中
- 支持横向和纵向滚动:通过
horizontal属性切换 - 支持分页加载:通过
onEndReached实现无限滚动 - 下拉刷新功能:通过
refreshControl实现 - 头部和尾部组件:通过
ListHeaderComponent和ListFooterComponent定制 - 空数据提示:通过
ListEmptyComponent显示空数据状态 - 支持项的自定义键:通过
keyExtractor提供唯一key - 性能优化:使用
initialNumToRender、getItemLayout等进行优化
Props
data
传递给
FlatList的数据源,通常是一个数组
<FlatList data={data} />
renderItem
一个函数,用来渲染列表项,接收一个参数(item 数据),并返回要渲染的内容
<FlatList
data={data}
renderItem={({ item }) => <Text>{item.title}</Text>}
/>
keyExtractor
用于为每个项生成唯一的
key。通常通过返回数据项的某个唯一字段来实现
<FlatList
data={data}
keyExtractor={item => item.id.toString()}
/>
keyboardDismissMode
同 ScrollView
keyboardShouldPersistTaps
同 ScrollView
horizontal
同 ScrollView
onEndReached
在列表滚动到底部时触发的回调,用于加载更多数据
<FlatList
data={data}
onEndReached={loadMoreData}
onEndReachedThreshold={0.5} // 设置触发的阈值
/>
onEndReachedThreshold
用来设置触发
onEndReached回调的阈值。该属性指定了距离列表底部的距离(以屏幕高度的比例或像素为单位)
当滚动到这个距离时,
onEndReached会被触发
使用比例(屏幕高度的百分比) :
<FlatList
data={data}
onEndReached={loadMoreData}
onEndReachedThreshold={0.5} // 当滚动到距离底部 50% 的位置时触发
/>
使用像素值:
<FlatList
data={data}
onEndReached={loadMoreData}
onEndReachedThreshold={100} // 当滚动到距离底部 100 像素时触发
/>
onRefresh
触发下拉刷新时调用的函数
refreshing
表示列表是否处于刷新状态
true:表示正在刷新,通常显示一个刷新指示器(例如:一个旋转的图标)。
false:表示刷新已完成,刷新指示器消失。
const [isRefreshing, setIsRefreshing] = useState(false);
const handleRefresh = () => {
setIsRefreshing(true);
// 模拟网络请求
setTimeout(() => {
setIsRefreshing(false);
// 更新数据
}, 2000);
};
<FlatList
data={data}
onRefresh={handleRefresh}
refreshing={isRefreshing}
/>
onScroll
监听滚动事件,通常用于跟踪滚动位置
<FlatList
data={data}
onScroll={(event) => console.log(event.nativeEvent.contentOffset.y)}
/>
getItemLayout
优化性能,当你知道列表项的高度或宽度时,可以直接指定,以便
FlatList可以快速计算布局,而不必逐个测量
<FlatList
data={data}
getItemLayout={(data, index) => (
{ length: 50, offset: 50 * index, index }
)}
/>
initialNumToRender
initialNumToRender属性指定了FlatList初次渲染时显示的列表项数量。剩余的项会在用户滚动时按需加载(懒加载)。
ListEmptyComponent
当
FlatList数据为空时渲染的组件
<FlatList
data={data}
ListEmptyComponent={<Text>No data available</Text>}
/>
ListHeaderComponent
渲染在列表顶部的组件
<FlatList
data={data}
ListHeaderComponent={<Text>Header</Text>}
/>
ListFooterComponent
渲染在列表底部的组件
<FlatList
data={data}
ListFooterComponent={<Text>Footer</Text>}
/>
viewabilityConfig
控制列表项的可见性检测配置
<FlatList
data={data}
viewabilityConfig={{
itemVisiblePercentThreshold: 50 // 只有超过 50% 的项才会被视为可见
}}
onViewableItemsChanged={onViewableItemsChanged}
/>
onViewableItemsChanged
当可见项发生变化时触发的回调函数
onViewableItemsChanged={({ viewableItems, changed }) => {
// viewableItems: 当前可见的项
viewableItems.forEach(({ item, index }) => {
console.log('Visible item:', item, 'at index', index);
});
// changed: 上次更新以来发生变化的项
changed.forEach(({ item, index, isViewable }) => {
console.log('Item changed:', item, 'at index', index, 'is now viewable:', isViewable);
});
}}
numColumns
用于定义列表每行显示的列数,通常用于实现网格布局(grid layout)。
<FlatList
data={data}
renderItem={({ item }) => <View>{/* 每个项目的内容 */}</View>}
numColumns={3} // 每行显示 3 列
/>
-
值类型:
numColumns是一个数字,表示每行要显示的项数 -
布局方向:当
numColumns设置为大于 1 时,FlatList的滚动方向通常会是垂直方向。如果你想要水平网格布局,则需要设置horizontal={true} -
自定义项的宽度:如果你使用
numColumns,要确保每个项的宽度合适。通常,FlatList会自动计算列的宽度,但你可以通过设置style来进一步调整每个项的布局
ItemSeparatorComponent
渲染每个项之间的分隔符。通常用于添加间隔或线条,帮助分隔列表项
<FlatList
data={data}
renderItem={({ item }) => <Text>{item}</Text>}
ItemSeparatorComponent={() => (
<View style={{ height: 1, backgroundColor: '#ddd' }} />
)}
/>
API
scrollToIndex
将列表滚动到指定的索引位置
flatListRef.current.scrollToIndex({ index: 10 });
scrollToOffset
将列表滚动到指定的偏移量
flatListRef.current.scrollToOffset({ offset: 100 });
scrollToEnd
将列表滚动到最后一项
flatListRef.current.scrollToEnd();
setNativeProps
直接向
FlatList组件的原生视图传递属性,通常用于性能优化
flatListRef.current.setNativeProps({ style: { backgroundColor: 'red' } });
SectionList
SectionList 是一个支持分组渲染的列表,适用于需要按类别、标题等方式分组显示数据的场景。
Props
sections
用于指定分组数据,每个分组包含一个
title和该组的data
const sections = [
{ title: 'Title 1', data: ['Item 1', 'Item 2', 'Item 3'] },
{ title: 'Title 2', data: ['Item 4', 'Item 5'] },
{ title: 'Title 3', data: ['Item 6'] },
];
renderItem
渲染每个项的内容,传递给它的数据项是
section.data中的元素
renderItem={({ item }) => <Text>{item}</Text>}
renderSectionHeader
渲染每个分区的标题(即每个 section 的
title)
renderSectionHeader={({ section }) => <Text>{section.title}</Text>}
stickySectionHeadersEnabled
设置是否启用粘性分区标题(即标题在滚动时固定在顶部)
默认值:
false
SectionList 实现一个分组列表:
import React from 'react';
import {SectionList, Text, View, StyleSheet} from 'react-native';
const sections = [
{ title: 'Fruits', data: ['Apple', 'Banana', 'Orange', 'Mango', 'Pineapple', 'Grapes', 'Peach', 'Strawberry', 'Blueberry', 'Kiwi'] },
{ title: 'Vegetables', data: ['Carrot', 'Broccoli', 'Spinach', 'Cucumber', 'Tomato', 'Potato', 'Onion', 'Garlic', 'Lettuce', 'Cabbage'] },
{ title: 'Dairy', data: ['Milk', 'Cheese', 'Yogurt', 'Butter', 'Cream', 'Ice Cream'] },
{ title: 'Meat', data: ['Chicken', 'Beef', 'Pork', 'Lamb', 'Turkey'] },
{ title: 'Beverages', data: ['Tea', 'Coffee', 'Juice', 'Soda', 'Water', 'Wine', 'Beer'] },
{ title: 'Snacks', data: ['Chips', 'Cookies', 'Candy', 'Chocolate', 'Nuts', 'Popcorn'] },
];
const MySectionList = () => {
return (
<SectionList
sections={sections}
renderItem={({item}) => (
<View style={styles.item}>
<Text>{item}</Text>
</View>
)}
renderSectionHeader={({section}) => (
<View style={styles.header}>
<Text style={styles.headerText}>{section.title}</Text>
</View>
)}
keyExtractor={(item, index) => item + index}
stickySectionHeadersEnabled={true}
ItemSeparatorComponent={() => <View style={styles.separator} />}
/>
);
};
const styles = StyleSheet.create({
item: {
padding: 10,
backgroundColor: '#f9f9f9',
},
header: {
backgroundColor: '#6F4F1F',
padding: 5,
},
headerText: {
color: '#fff',
fontWeight: 'bold',
},
separator: {
height: 1,
backgroundColor: '#ccc',
},
});
export default MySectionList;

SectionList 有很多属性是跟 FlatList 一样的:
keyExtractor
同 FlatList
ListHeaderComponent
同 FlatList
ListFooterComponent
同 FlatList
onEndReached
同 FlatList
onEndReachedThreshold
同 FlatList
refreshing
同 FlatList
onRefresh
同 FlatList
ItemSeparatorComponent
同 FlatList
getItemLayout
同 FlatList
initialNumToRender
同 FlatList
horizontal
同 FlatList
onViewableItemsChanged
同 FlatList
keyboardDismissMode
同 FlatList
keyboardShouldPersistTaps
同 FlatList
RefreshControl
用于实现下拉刷新功能的组件,通常和 ScrollView、FlatList 或 SectionList 一起使用。它能够在用户下拉列表时触发刷新事件,通常用于加载新的数据或刷新页面内容。
Props
refreshing (必填)
控制刷新指示器的显示和隐藏。如果值为
true,则显示刷新动画;如果值为
false,则隐藏刷新动画。
onRefresh(必填)
当用户触发下拉刷新时调用的回调函数。通常在这个函数内会进行数据请求或状态更新操作。
tintColor
设置刷新指示器的颜色
使用 RefreshControl 与 FlatList 配合实现下拉刷新功能:
import React, { useState } from 'react';
import { FlatList, Text, View, RefreshControl, StyleSheet } from 'react-native';
const MyFlatList = () => {
const [data, setData] = useState(['Item 1', 'Item 2', 'Item 3']);
const [isRefreshing, setIsRefreshing] = useState(false);
const handleRefresh = () => {
setIsRefreshing(true);
// 模拟网络请求
setTimeout(() => {
// 假设数据已刷新
setData(['Item 4', 'Item 5', 'Item 6']);
setIsRefreshing(false);
}, 2000); // 2秒后刷新完成
};
return (
<FlatList
data={data}
renderItem={({ item }) => <Text style={styles.item}>{item}</Text>}
keyExtractor={(item, index) => index.toString()}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={handleRefresh}
tintColor="#0000ff"
/>
}
/>
);
};
const styles = StyleSheet.create({
item: {
padding: 20,
borderBottomWidth: 1,
borderBottomColor: '#ccc',
},
});
export default MyFlatList;

不同滚动组件的区别
ScrollView
特点:
- 用于滚动容器,可以包含任何类型的子组件
- 渲染所有子项:
ScrollView会一次性渲染所有子元素,适用于数据量较小的场景 - 不支持虚拟化:
ScrollView会将所有内容都渲染到内存中,不做懒加载,因此对于大数据列表不够高效
FlatList
特点:
- 专门为长列表优化,支持高效的虚拟化(仅渲染当前视口内的项)。
- 支持分页加载、懒加载等优化,大数据量时表现更好
- 只支持一维数据列表,即一个简单的数组
SectionList
特点:
- 用于渲染带有分组数据的列表
- 支持每个分组的头部,通常用于展示带有分组的复杂数据(如按类别分的商品、按时间分的事件等)
- 也支持虚拟化,因此对于大量数据的渲染效率较高
总结对比
| 特性 | ScrollView | FlatList | SectionList |
|---|---|---|---|
| 用途 | 用于简单的滚动视图,包含多个组件 | 用于展示一维列表(不支持分组) | 用于展示带有分组标题的数据 |
| 数据结构 | 任意内容,适用于少量内容或固定内容 | 一维数据列表(数组) | 分组数据(每个组包含一个 title 和 data 数组) |
| 性能 | 不支持虚拟化,适用于小数据量 | 支持虚拟化,适用于大数据量 | 支持虚拟化,适用于大数据量且需要分组的情况 |
| 支持的功能 | 可以嵌套不同类型的子组件 | 支持懒加载、分页加载、滚动到指定项等功能 | 支持渲染分组数据和分组标题,适合展示分组列表 |
| 适用场景 | 数据量少,页面布局较为简单 | 长列表、大数据量的单一列表项 | 需要分组显示的长列表,例如联系人、新闻类别等 |
选择依据:
- 如果是简单的内容展示和小数据量,使用
ScrollView - 如果是大数据量的单一列表,选择
FlatList - 如果是大数据量并且需要分组显示,选择
SectionList