ReeelScroll
This page has not been translated into English yet. The Russian original is below.
Прокручиваемый список с поддержкой фокуса и клавиатурного управления. Поддерживает вертикальную и горизонтальную прокрутку, вложенные скроллы с делегацией навигации.
Тип:
multi-child
ReeelScroll itemCount:3
#config direction:horizontal spacing:20
@Macros id:itemBuilder index:0 isFocused:false
Text $"Элемент ${index}"
Два режима работы
1. Macro mode — для однотипных элементов
Требуется
itemCount
+
@Macros id:itemBuilder
. Каждый элемент строится по одному шаблону. Идеален с
#data
для data-driven списков.
ReeelScroll itemCount:5
#config direction:horizontal spacing:24
#padding symmetric horizontal:80
#data
:# title:"Фильм 1" badge:"4K"
:# title:"Фильм 2" badge:"HDR"
:# title:"Фильм 3" badge:"Новое"
:# title:"Фильм 4" badge:"TOP"
:# title:"Фильм 5" badge:"4K"
@Macros id:itemBuilder index:0 isFocused:false
$MovieCard title:{data[index]['title']} badge:{data[index]['badge']}
@Macros id:selectorBuilder isFocused:false
DecoratedBox
#decoration
#borderRadius circular 20
#border fromBorderSide
#side color:{isFocused ? $focusColor : 0x00} width:3
2. Children mode — для разнородных элементов
Без
itemCount
и
@Macros id:itemBuilder
. Дочерние элементы (кроме макросов) используются напрямую как items списка.
itemCount
определяется автоматически по количеству дочерних.
ReeelScroll
#config direction:vertical spacing:42
// Каждый дочерний элемент — отдельный item скролла
// Column внутри вертикального скролла — обязательно size:min
Column crossAxisAlignment:stretch mainAxisSize:min
$NavBar
$HeroBanner
Column crossAxisAlignment:start spacing:24 mainAxisSize:min
$SectionHeader "Рекомендации"
SizedBox height:288
// Вложенный горизонтальный скролл (macro mode)
ReeelScroll itemCount:6
#config direction:horizontal spacing:24
@Macros id:itemBuilder index:0 isFocused:false
$Card title:{data[index]['title']}
$PromoBanner title:"Промо" subtitle:"Текст" buttonText:"Кнопка"
SizedBox height:80
@Macros id:selectorBuilder isFocused:false
SizedBox
Параметры
| Параметр | Тип | Default | Описание |
|---|---|---|---|
itemCount
|
int | children.length | Количество элементов (обязателен в macro mode, опционален в children mode) |
initialIndex
|
int | 0 | Начальный индекс фокуса |
autofocus
|
bool | false | Автоматический захват фокуса при создании |
onIndexChanged
|
callback | — |
(index, isFocused){...}
— вызывается при смене фокуса
|
onSelect
|
callback | — |
(index){...}
— вызывается при выборе элемента (Enter/OK)
|
Конфигурация (
#config
)
ReeelScroll itemCount:10
#config direction:horizontal spacing:20 shrinkWrap:true
#padding symmetric horizontal:50
| Параметр | Тип | Default | Описание |
|---|---|---|---|
direction
|
vertical / horizontal | vertical | Направление прокрутки |
spacing
|
double | 0 | Расстояние между элементами |
crossSpacing
|
double | 0 | Расстояние по поперечной оси (для grid) |
shrinkWrap
|
bool | false | Размер по содержимому (без бесконечной прокрутки) |
clampEdges
|
bool | true | Ограничение прокрутки краями содержимого |
enableDragScroll
|
bool | true | Поддержка перетаскивания мышью |
keepAliveEnabled
|
bool | false | Сохранять состояние невидимых элементов |
cacheExtent
|
double | — | Область предзагрузки за пределами видимой области |
scrollWheelSensitivity
|
double | 1.0 | Чувствительность колёсика мыши |
defaultBehavior
|
center / ensureVisible | center | Поведение позиционирования при фокусе |
Отступы
#config direction:horizontal
#padding symmetric horizontal:80
// или
#padding only left:80 top:20
// или
#padding all:20
Grid-раскладка
#config direction:vertical
#gridDelegate fixedCount 3 // 3 колонки
// или
#gridDelegate maxExtent 200 // максимальная ширина элемента 200
Анимация прокрутки
#config
#animationConfig curved
curve:easeOutCubic
duration:300ms
// или
#animationConfig spring
stiffness:200.0
damping:25.0
Макросы-билдеры
Все макросы-билдеры работают в обоих режимах (macro и children).
itemBuilder
(только macro mode)
Шаблон для построения каждого элемента. Получает
index
и
isFocused
:
@Macros id:itemBuilder index:0 isFocused:false
Text $"Элемент ${index}, фокус: ${isFocused}"
selectorBuilder
Декоратор фокуса — оборачивает каждый элемент. Получает
isFocused
:
@Macros id:selectorBuilder isFocused:false
DecoratedBox
#decoration
#borderRadius circular 20
#border fromBorderSide
#side color:{isFocused ? $focusColor : 0x00} width:3
separatorBuilder
Разделитель между элементами. Получает
index
:
@Macros id:separatorBuilder index:0
SizedBox width:1
ColoredBox color:$dividerColor
underlayBuilder
Фон под каждым элементом. Получает
index
:
@Macros id:underlayBuilder index:0
ColoredBox color:0xffc0c0c0
#data
+ индексный доступ
Data-driven подход для однотипных элементов. Данные описываются в
#data
через позиционные структуры (
:#
), доступ — через
{data[index]['field']}
:
ReeelScroll itemCount:4
#config direction:horizontal spacing:24
#padding symmetric horizontal:80
#data
:# title:"Звёздные врата" subtitle:"Сезон 3, Серия 7" progress:0.67
:# title:"Тёмная башня" subtitle:"Сезон 1, Серия 4" progress:0.45
:# title:"Хроники Нарнии" subtitle:"Сезон 2, Серия 1" progress:0.12
:# title:"Мандалорец" subtitle:"Сезон 3, Серия 2" progress:0.89
@Macros id:itemBuilder index:0 isFocused:false
$ContinueWatchingCard
title:{data[index]['title']}
subtitle:{data[index]['subtitle']}
progress:{data[index]['progress']}
Преимущества:
- Данные отделены от шаблона — один макрос карточки для всех элементов
- Компактнее, чем Switcher с N вариантами
- Готовность к будущим генераторам (загрузка данных с сервера)
Примеры
Горизонтальный скролл карточек с
#data
SizedBox height:288
ReeelScroll itemCount:6
#config direction:horizontal spacing:24
#padding symmetric horizontal:80
#data
:# badge:"Боевик"
:# badge:"Драма"
:# badge:"Комедия"
:# badge:"Триллер"
:# badge:"Фантастика"
:# badge:"Детектив"
@Macros id:itemBuilder index:0 isFocused:false
$HorizontalCard badge:{data[index]['badge']}
@Macros id:selectorBuilder isFocused:false
DecoratedBox
#decoration
#borderRadius circular 24
#border fromBorderSide
#side color:{isFocused ? $focusColor : 0x00} width:3
Вертикальный скролл страницы (children mode)
ReeelScroll
#config direction:vertical spacing:42
#padding only top:0
// Секция 1 — шапка (size:min — обязательно для Column в вертикальном скролле)
Column crossAxisAlignment:stretch mainAxisSize:min
$NavBar
$HeroBanner
// Секция 2 — карусель рекомендаций
Column crossAxisAlignment:start spacing:24 mainAxisSize:min
$SectionHeader "Рекомендации"
SizedBox height:288
ReeelScroll itemCount:6
#config direction:horizontal spacing:24
#padding symmetric horizontal:80
#data
:# title:"Фильм 1" badge:"4K"
:# title:"Фильм 2" badge:"HDR"
@Macros id:itemBuilder index:0 isFocused:false
$MovieCard title:{data[index]['title']} badge:{data[index]['badge']}
@Macros id:selectorBuilder isFocused:false
DecoratedBox
#decoration
#borderRadius circular 20
#border fromBorderSide
#side color:{isFocused ? $focusColor : 0x00} width:3
// Секция 3 — баннер
$PromoBanner title:"Промо" subtitle:"Текст акции" buttonText:"Подробнее"
// Footer
SizedBox height:80
@Macros id:selectorBuilder isFocused:false
SizedBox
Смешанные типы в itemBuilder (Switcher +
#data
)
Когда первый элемент структурно отличается от остальных:
ReeelScroll itemCount:7
#config direction:horizontal spacing:24
#padding symmetric horizontal:80
@Macros id:itemBuilder index:0 isFocused:false
Switcher $index
// Default — обычная карточка
$VerticalCard rating:"7.0" badge:"4K"
// Первый элемент — промо-карточка
$PromoCard id:0 price:"12$" subtitle:"в месяц"
$VerticalCard id:1 rating:"8.5" badge:"Новое"
$VerticalCard id:2 rating:"7.8" badge:"4K"
$VerticalCard id:3 rating:"9.1" badge:"TOP"
Bad practices
Switcher с N однотипными элементами вместо
#data
// BAD — дублирование шаблона, данные вшиты в каждый вариант
@Macros id:itemBuilder index:0 isFocused:false
Switcher $index
$Card title:"Третий"
$Card id:0 title:"Первый"
$Card id:1 title:"Второй"
// GOOD — данные отделены, один шаблон
#data
:# title:"Первый"
:# title:"Второй"
:# title:"Третий"
@Macros id:itemBuilder index:0 isFocused:false
$Card title:{data[index]['title']}
itemBuilder + Switcher для разнородных секций
// BAD — вынужденный Switcher с десятком вариантов
ReeelScroll itemCount:10
@Macros id:itemBuilder index:0 isFocused:false
Switcher $index
SizedBox height:80
Column id:0
$NavBar
Column id:1
$SectionHeader "Рекомендации"
...9 дочерних с id...
// GOOD — children mode, каждая секция = прямой дочерний элемент
ReeelScroll
Column mainAxisSize:min
$NavBar
Column mainAxisSize:min
$SectionHeader "Рекомендации"
...
SizedBox height:80
Best practices
-
Macro mode +
#dataдля однотипных списков (карточки, чипсы, табы) - Children mode для разнородных секций (страницы с разными блоками)
-
Данные отдельно от шаблона
:
#dataс:#-элементами +{data[index]['field']}в itemBuilder -
selectorBuilderдля визуального фокуса — бордер, тень, масштаб -
Вложенные скроллы
: внешний (vertical, children mode) + внутренние (horizontal, macro mode с
#data)
Column/Row внутри скролла —
size:min
Column
и
Row
по умолчанию имеют
size:max
и пытаются занять всё доступное пространство по главной оси. Внутри
ReeelScroll
каждый item получает
maxHeight
/
maxWidth
, равный viewport'у. Это значит:
-
Column
(главная ось — vertical) с
size:maxвнутри вертикального скролла растянется на весь viewport -
Row
(главная ось — horizontal) с
size:maxвнутри горизонтального скролла растянется на весь viewport
В обоих случаях первый элемент займёт весь экран, вытеснив остальные секции.
Правило: Column/Row как прямой item скролла по той же оси → всегда
size:min
.
// BAD — секции невидимы, первый Column занимает весь viewport
ReeelScroll
#config direction:vertical spacing:42
Column crossAxisAlignment:stretch
$NavBar
$HeroBanner
Column crossAxisAlignment:start spacing:24
$SectionHeader "Рекомендации"
...
// GOOD — каждая секция занимает ровно столько, сколько нужно
ReeelScroll
#config direction:vertical spacing:42
Column crossAxisAlignment:stretch mainAxisSize:min
$NavBar
$HeroBanner
Column crossAxisAlignment:start spacing:24 mainAxisSize:min
$SectionHeader "Рекомендации"
...
Это не влияет на cross-axis: Column с
size:max
внутри
горизонтального
скролла безопасен (cross-axis ограничен viewport'ом).
Ограничение размера дочерних элементов
Если дочерний элемент скролла не имеет естественного ограничения по главной оси (Column, Row без
size:min
, неограниченный контейнер), оберни его в
SizedBox
с явным размером:
// Горизонтальный вложенный скролл — ограничен по height (cross-axis)
SizedBox height:288
ReeelScroll itemCount:6
#config direction:horizontal spacing:24
...
// Элемент скролла без intrinsic height — ограничен SizedBox
ReeelScroll
#config direction:vertical
SizedBox height:700
Stack
...
See also
- Switcher — условный рендеринг внутри itemBuilder для смешанных типов элементов