Компонент ScrollView в React Native — контейнер с возможностью прокрутки содержимого, которое превышает размеры экрана. В отличие от FlatList, ScrollView рендерит всё содержимое сразу, что оптимально для небольших объёмов данных, форм и экранов с известной высотой. По данным React Native Docs, 2024, ScrollView поддерживает вертикальную и горизонтальную прокрутку, событие onScroll, программное управление позицией, а также жесты зума. Компонент рендерится в нативный UIScrollView на iOS и ScrollView на Android.
Главное
ScrollView — это компонент React Native, который оборачивает своё содержимое в прокручиваемый контейнер. Если контент выходит за границы экрана, пользователь может пролистывать его вертикально или горизонтально. ScrollView рендерит все дочерние элементы при монтировании, независимо от того, visible они на экране или нет.
В отличие от FlatList, который рендерит только видимые элементы (lazy rendering), ScrollView создаёт все нативные представления сразу. Это делает ScrollView удобным для форм, страниц настроек, карточек товаров на одном экране — везде, где количество дочерних элементов невелико (до 20-30) или их точное количество заранее неизвестно.
По данным React Native Using ScrollView, 2024, ScrollView поддерживает вложенную прокрутку (например, ScrollView внутри ScrollView), bounce-эффект при достижении края, индикаторы прокрутки, закрепление позиции (snap) и обработку жестов. На iOS ScrollView автоматически добавляет отступ под SafeArea через contentInsetAdjustmentBehavior.
ScrollView предоставляет богатый набор пропсов для управления поведением прокрутки, внешним видом и интерактивностью. Рассмотрим ключевые группы: управление скроллом, визуальные настройки, события и платформенные особенности.
horizontal — переключает направление прокрутки с вертикального (по умолчанию) на горизонтальное. scrollEnabled — отключает прокрутку при необходимости. showsVerticalScrollIndicator и showsHorizontalScrollIndicator управляют отображением индикаторов скролла. bounces (iOS) включает/отключает bounce-эффект при достижении края контента.
Основное событие — onScroll, которое вызывается при каждом скролле и передаёт объект с nativeEvent, содержащим contentOffset (текущая позиция), contentSize (размер контента), layoutMeasurement (размер видимой области). onMomentumScrollEnd вызывается после завершения инерционного скролла. onScrollEndDrag — когда пользователь отпустил экран. Эти события используются для реализации бесконечной прокрутки, параллакса и lazy loading.
ScrollView предоставляет методы для программного управления через реф: scrollTo({x, y, animated}) прокручивает к указанным координатам, scrollToEnd({animated}) — в конец содержимого, flashScrollIndicators() — временно показывает индикаторы скролла.
const scrollRef = useRef(null);
// Scroll to top
scrollRef.current.scrollTo({ x: 0, y: 0, animated: true });
// Scroll to end
scrollRef.current.scrollToEnd({ animated: true });
Программное управление скроллом часто используется в чатах (автоскролл к последнему сообщению), формах (скролл к полю с ошибкой) и каруселях (программное перелистывание).
Выбор между ScrollView и FlatList — одно из ключевых архитектурных решений в React Native. Оба компонента обеспечивают прокрутку, но используют принципиально разные стратегии рендеринга. ScrollView рендерит всё сразу, FlatList — только видимые элементы.
| Характеристика | ScrollView | FlatList |
|---|---|---|
| Рендеринг | Все элементы сразу | Только видимые + buffer |
| Производительность | Падает при 30+ элементах | Стабильна при любом количестве |
| Содержимое | Любые компоненты (формы, карточки) | Однотипные элементы из массива |
| Размер данных | Малый и средний (до 30 элементов) | Большой и неограниченный |
| Горизонтальный скролл | Да (пропс horizontal) | Да (horizontal) |
| Секции | Нет (рендерит как есть) | SectionList для секций |
Правило выбора: ScrollView — для экранов, где количество дочерних элементов известно и не превышает 20-30 (профиль пользователя, форма настройки, страница товара). FlatList — для списков с потенциально большим количеством элементов (лента новостей, каталог товаров, сообщения чата). Если контент разнородный (заголовок, форма, карточка, футер) — ScrollView предпочтительнее, так как FlatList ожидает однотипные элементы.
ScrollView поддерживает горизонтальную прокрутку через пропс horizontal, что делает его идеальным для каруселей, галерей изображений, вкладок и горизонтальных списков. В сочетании с пропсом pagingEnabled (iOS) или snapToInterval ScrollView превращается в компонент для постраничной навигации.
Свойство horizontal переключает направление прокрутки. pagingEnabled (iOS) включает постраничную прокрутку, при которой скролл останавливается только на границах элементов. snapToInterval задаёт шаг привязки в пикселях для обеих платформ.
const ImageCarousel = ({ images }) => (
<ScrollView
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onMomentumScrollEnd={handlePageChange}
>
{images.map((img, index) => (
<Image
key={index}
source={{ uri: img }}
style={{ width: SCREEN_WIDTH, height: 250 }}
/>
))}
</ScrollView>
);
В этой карусели pagingEnabled автоматически привязывает скролл к границам каждого изображения. onMomentumScrollEnd позволяет обновлять индикатор текущей страницы. Такая карусель работает нативно и поддерживает инерционный скролл.
Для нестандартных шагов привязки используется snapToInterval (размер шага в пикселях) и snapToAlignment (start, center, end). С помощью snapToOffsets можно задать массив конкретных позиций для привязки. Это полезно для горизонтальных списков с карточками разного размера.
Рассмотрим два типовых сценария: экран с формой (вертикальный скролл) и горизонтальный список категорий. Оба используют ScrollView с различными пропсами для оптимального поведения.
Страница редактирования профиля содержит разнородные элементы: аватар, несколько полей ввода, переключатели и кнопку сохранения. ScrollView позволяет скроллить всю страницу целиком, а не каждый блок отдельно.
const ProfileScreen = () => (
<ScrollView
contentContainerStyle={styles.container}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
<AvatarPicker />
<TextInput placeholder="Name" />
<TextInput placeholder="Email" />
<TextInput placeholder="About me" multiline />
<SwitchRow label="Notifications" />
<Button title="Save" />
</ScrollView>
);
Пропс keyboardShouldPersistTaps: 'handled' позволяет скроллить и взаимодействовать с формой, когда клавиатура открыта. contentContainerStyle применяет отступы ко всему содержимому. Этот паттерн используется во всех экранах с формами в React Native.
Для навигации по категориям (чаты, фильтры, вкладки) используется горизонтальный ScrollView с чипсами. Такой компонент часто встречается в приложениях маркетплейсов и соцсетей.
const CategoryChips = ({ categories, selected, onSelect }) => (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.chipContainer}
>
{categories.map((cat) => (
<Chip
key={cat.id}
label={cat.name}
isSelected={selected === cat.id}
onPress={() => onSelect(cat.id)}
/>
))}
</ScrollView>
);
Горизонтальный ScrollView с отключённым индикатором — стандарт для ленты категорий. Каждый чип — отдельный компонент с состоянием выбора. Пропс showsHorizontalScrollIndicator: false убирает полосу прокрутки, что соответствует ожиданиям пользователей мобильных приложений.
Часто задаваемые вопросы
ScrollView подходит для небольших объёмов данных (до 20-30 элементов) и разнородного контента (формы, профили, экраны настроек). FlatList выбирайте для длинных однотипных списков — новостная лента, каталог товаров, сообщения.
Используйте событие onScroll с onScrollEndDrag или onMomentumScrollEnd. В nativeEvent.contentOffset.y содержится текущая вертикальная позиция. Для производительности используйте ScrollEventThrottle (iOS) для настройки частоты вызова onScroll.
ScrollView рендерит все элементы при монтировании, создавая нативные представления для каждого. При 50+ элементах на экране нагрузка на память и JS-поток растёт, вызывая дроп фреймов. Для таких случаев используйте FlatList с lazy-рендерингом.
Установите bounces={false}. Этот пропс работает только на iOS и отключает пружинистый эффект при достижении края ScrollView. На Android bounce-эффекта нет по умолчанию, поэтому пропс игнорируется.
ScrollView не поддерживает бесконечную прокрутку нативно. Однако можно комбинировать onScroll с проверкой приближения к нижнему краю (contentOffset.y + высота экрана >= contentSize.height) и добавлять элементы в состояние. Для серьёзных объёмов используйте FlatList с onEndReached.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также