REEEL Layout Best Practices
This page has not been translated into English yet. The Russian original is below.
Практические правила вёрстки в REEEL-формате, основанные на особенностях рендеринга Flutter.
Архитектурные правила приложений (поток данных, навигация, генераторы, каркас) — в architecture.md .
Адаптивная вёрстка сайта — что решает CSS, что рантайм и по чему это видно — в responsive.md .
Что стоит на стволе страницы — скроллер, липкая шапка, накладки — в page_root.md .
Border + Padding: зазор между рамкой и контентом
DecoratedBox
рисует border
внутрь
своих bounds.
Padding
отодвигает ребёнка от края. Зазор между внутренним краем рамки и ребёнком:
зазор = padding - borderWidth
Если
padding == borderWidth
— зазора нет, рамка вплотную к контенту.
// borderWidth 4, padding 8 → зазор 4px
DecoratedBox
#decoration
#border fromBorderSide
#side color:$primaryFocusedColor width:4
Padding
#padding all 8
// child начинается в 8px от края, рамка заканчивается в 4px → 4px зазор
// borderWidth 4, padding 4 → зазор 0px (рамка вплотную!)
DecoratedBox
#decoration
#border fromBorderSide
#side color:$primaryFocusedColor width:4
Padding
#padding all 4
// child начинается в 4px от края = внутренний край рамки → зазора нет
Параллельные скругления
Чтобы скругление внешней рамки шло параллельно скруглению внутреннего контента:
outerRadius = innerRadius + padding
// inner 20 + padding 8 = outer 28
DecoratedBox
#decoration
#borderRadius circular 28
#border fromBorderSide
#side color:$color width:4
Padding
#padding all 8
ClipRRect
#borderRadius circular 20
// card content
SizedBox и DecoratedBox с border
SizedBox
с фиксированным размером должен быть
внутри
Padding
, а не снаружи
DecoratedBox
. Иначе
DecoratedBox
зажат в размер карточки и не может вырасти для рамки + зазора.
// Правильно — рамка адаптируется под card + padding
DecoratedBox
#decoration
#border fromBorderSide
#side color:$color width:4
Padding
#padding all 8
SizedBox width:288 height:512
ClipRRect
#borderRadius circular 20
Stack ...
// Неправильно — рамка зажата в 288x512, padding ещё больше сжимает контент
SizedBox width:288 height:512
DecoratedBox
#decoration
#border fromBorderSide
#side color:$color width:4
Padding
#padding all 8
ClipRRect
Stack ...
Stack: размер определяется первым non-positioned ребёнком
Center
,
Align
и
Positioned
внутри
Stack
зависят от размера
Stack
. Размер
Stack
определяется non-positioned children. Первый такой ребёнок задаёт базовый размер:
Stack
SizedBox width:280 height:500 // задаёт размер Stack
ColoredBox color:$bgColor
Positioned top:13 right:13 // позиция относительно 280x500
$Badge "Lable"
Center // центрируется в 280x500
Icon play_arrow size:30
Без
SizedBox
с фиксированным размером
Center
и
Positioned
не будут работать как ожидается.
Фокус: карточки vs кнопки
Два паттерна управления фокусом:
Кнопки — собственный фокус через
FocusableActionDetector
@PrimaryButton @isFocused:false onPressed:null text:"button"
FocusableActionDetector isFocused:$isFocused onPressed:$onPressed
DecoratedBox
#decoration
#border fromBorderSide
#side color:{isFocused ? primaryFocusedColor : 0x00} width:3
// button content
Карточки — фокус приходит извне из
ReeelScroll
Карточки получают
isFocused
через параметр макроса. В
ReeelScroll
фокус передаётся через
@Macros id:itemBuilder
:
// Определение макроса карточки (без FocusableActionDetector)
@VerticalCard @isFocused:false rating:"" badge:""
DecoratedBox
#decoration
#border fromBorderSide
#side color:{isFocused ? primaryFocusedColor : 0x00} width:4
Padding
#padding all 8
// card content
// Использование в ReeelScroll
ReeelScroll itemCount:6
@Macros id:itemBuilder index:0 isFocused:false
$VerticalCard rating:"8.5" badge:"4K"