Контейнеры UI
Структурные элементы: UIColumn стекает детей вертикально, UIRow — горизонтально, UIScrollable
делает область переполнения панируемой, UISpacer съедает свободное место. Для целого экрана,
который прокручивается, предпочитай UIScreen.makeScrollable() оборачиванию всего в UIScrollable —
см. screen-router.md.
Обзор
const screen = UIScreen([
UIRow([
UIText("Library").style({ fontSize: 24, fontWeight: 700, color: "white" }),
UISpacer(), // толкает счётчик к дальнему краю
UIText("12 items").style({ color: "#888" }),
]).style({ px: 16, py: 12, alignItems: "center" }),
UIScrollable([
UIColumn([ UIText("First").style({ color: "white" }) ]).style({ p: 16 }),
UIColumn([ UIText("Second").style({ color: "white" }) ]).style({ p: 16 }),
]).style({ flexGrow: 1, flexShrink: 1, gap: 8 }) // flexShrink: 1 иначе переполнится
.onScroll(pos => console.log("scrolled to", pos)),
]).style({ bgColor: "black", pt: "safe-top" })
screen.open()UIRow / UIColumn
UIColumn(): UIColumn
UIColumn(children: UINodeChild[]): UIColumn
UIRow(children: UINodeChild[]): UIRow // без перегрузки без аргументов — используй UIRow([])Единственная разница между ними — дефолтный flexDirection (column против row) — оба принимают
полную поверхность стиля контейнера (UIContainerStyle = свойства элемента + рисуемого + раскладки
контейнера, см. styling.md). Записи-дети, равные null / undefined /
false, пропускаются — см. overview.md.
Избегай контейнеров-обёрток, существующих только для выравнивания чего-то — выравнивание это свойство контейнера:
UIRow([ UIColumn([]).style({ flexGrow: 1 }), label ]) // ✗ фантомный элемент-распорка
UIRow([ label ]).style({ justifyContent: "flex-end" }) // ✓Управление детьми
Все контейнеры на этой странице делят один императивный API детей (работает до и после появления элемента на экране; без диффинга):
c.append(...nodes: UINodeChild[]): this
c.insert(index: number, ...nodes: UINodeChild[]): this // индекс в c.children
c.remove(...nodes: UINode[]): this // удаляет по идентичности
c.setContent(children: UINodeChild[]): this // заменить всё
c.children // readonly UINodeChild[]setContent — примитив «ре-рендера» — построй свежий массив (напр. items.map(Row)) и подмени его.
Для длинных или неограниченных данных используй UIVirtualizedList.
UIBox — устарел
UIBox(children | style | (style, children)): UIBox // легаси — используй UIRow / UIColumnЛегаси-контейнер, чьё единственное отличие — дефолт justifyContent и alignItems в "center"
(дети центрированы по обеим осям). Оставлен для старых проектов; новый код пиши с UIRow/UIColumn
плюс явное выравнивание.
UIScrollable
Панируемая область переполнения внутри в остальном фиксированной раскладки — список под
закреплённой шапкой, горизонтальная карусель. Если весь экран — один поток (статья, лента), сделай
прокручиваемым сам экран: pull-to-refresh (onRefresh) есть только на
UIScreen.makeScrollable().
UIScrollable(): UIScrollable
UIScrollable(children: UINodeChild[]): UIScrollableДополнительные стили поверх поверхности контейнера:
scrollDirection: "horizontal" | "vertical" // по умолчанию vertical
showScrollbar: boolean
overscrollMode: "none" | "absorb" | "default" // поведение края при протягивании за контентСобытия прокрутки (чейнятся, как все on*):
s.onScroll(cb: (scrollPosition: number) => void): UIScrollable // логические px от стартового края
s.onScrollRelease(cb: () => void): UIScrollable // палец поднят
s.onOverscroll(cb: (delta: number) => void): UIScrollable // протянут за край (px)scrollTo нет — позицию UIScrollable нельзя задать программно. Это текущее ограничение. Если
нужна программная прокрутка (scrollTo / scrollToEnd / scrollToKey), используй
UIVirtualizedList.
flexShrink по умолчанию 0 везде, поэтому вертикальный UIScrollable в колонке переполняет экран
вместо прокрутки, пока он — и любые оборачивающие контейнеры между ним и экраном — не получат
flexShrink: 1.
Горизонтальная карусель:
UIScrollable(items.map(Card))
.style({ scrollDirection: "horizontal", showScrollbar: false, gap: 12, px: 16 })Перетаскиваемым детям внутри скроллера нужно claim их направление жеста, иначе прокрутка украдёт
указатель — см. touch.md.
UISpacer
UISpacer(): UISpacer // без детей; его поверхность стиля — только ElementStyle — без фонаГибкое пустое место: по умолчанию flexGrow: 1, съедает свободное место вдоль главной оси родителя.
Тянись к нему, только когда обычное выравнивание не выражает раскладку — один элемент, толкнутый к
дальнему краю, пока остальные стоят:
UIRow([ title, UISpacer(), closeButton ])Если все дети двигаются вместе, justifyContent ("space-between", "flex-end", …) делает ту же
работу без лишнего элемента.
Смотрите также
- Модель элементов UI — массивы детей, условный рендер, ссылки.
- Стилизация — словарь стиля контейнера (
gap,alignItems, …). - Экраны и навигация —
UIScreen.makeScrollable(),onRefresh. - Виртуализированные списки — оконный рендер + программная прокрутка.