Спросите помощника
0/400
Вопрос обрабатывается ИИ-сервисом и сохраняется для улучшения ответов. Не вводите персональные данные.

    REEEL Layout Best Practices

    Практические правила вёрстки в 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"
    menu_baseline