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

    Корень страницы: скроллер, шапка, накладки

    Правило структурное, а не про адаптивность: оно о том, что стоит на СТВОЛЕ страницы. Адаптивная вёрстка — в responsive.md .

    Правило

    Страница объявляет скроллер одним CustomScrollView на стволе. Что липнет к потоку — сливер внутри него. Что лежит поверх — Positioned рядом со скроллером в том же Stack . Что меряет страницу ( ScrollData ) — стоит НАД скроллером.

    ScrollData progress:@p          // читает скроллер под собой
      Stack clipBehavior:none       // окно — только если есть накладки
        CustomScrollView            // скроллер страницы: ровно один, на стволе
          PinnedHeaderSliver        // шапка в потоке
            $Header
          Column crossAxisAlignment:stretch size:min
            …секции…                // бокс прямым ребёнком законен
        Positioned top:0 left:0 right:0 height:3   // накладка
          $Progress

    Почему на сайте это не «лишний» элемент

    На сайте документ прокручивается сам, поэтому страница без скроллера выглядит рабочей и живёт годами. В приложении этого нет: превью отдаёт корню жёсткие ограничения, и страница уходит в сплошной overflow — борд правки её не открывает вовсе. Одна и та же разметка обязана работать в обоих рендерах, и именно скроллер делает её таковой. Анализатор говорит об этом заранее — советом page_without_scroller .

    Накладка — форма, а не параметр

    Positioned , лежащий в Stack рядом со скроллером страницы, прибивается к окну. Никакого слова для этого не нужно: во Flutter Stack берёт размер непозиционированного ребёнка — скроллвью, то есть окна, — поэтому позиционированный сосед стоит, пока содержимое едет. Веб читает ту же форму и эмитит position: fixed .

    Positioned в любом ДРУГОМ Stack остаётся со своим Stack и уезжает вместе с ним — в обоих рендерах одинаково. Это и есть разница, которую рисует форма: кладите слой туда, где имеете в виду.

    Три ловушки

    Сливер вне скроллвью роняет экран целиком ( _RenderPinnedHeaderSliver is not a subtype of RenderBox ) — не «рисуется не так», а не открывается. Обратное безопасно: бокс прямым ребёнком CustomScrollView законен, скроллвью сам заворачивает его в SliverToBoxAdapter .

    Клип на стволе прячет скроллер страницы. У Stack по умолчанию clipBehavior: hardEdge , то есть overflow: hidden . Компилятор ищет скроллер спуском по стволу и снимает с него overflow , чтобы крутился документ, — но клип он не трогает намеренно: его поставил автор, и снятый клип вернул бы на страницу то, что прятали. Спуск на клипе прекращается, крутится вложенный элемент, и липкая шапка уезжает вместе со страницей. Отсюда clipBehavior:none у корневого Stack . Бокс с заданной height на стволе останавливает спуск так же.

    Шапка в потоке занимает своё место. Плавающая не занимала — значит, верхний отступ первой секции надо уменьшить ровно на её высоту. Высота обычно дробная (измеренные 81,5625 и 65,9375 px), поэтому совпадение будет с точностью до доли пикселя; подгонять распорку под метрику шрифта не стоит. И задавать её надо элементом ( SizedBox height:{…} ), а не #padding : объект отступов не читает переменную дерева.

    ScrollData стоит НАД скроллером

    ScrollData заводит собственный контроллер и раздаёт его поддереву, а CustomScrollView под ним этот контроллер берёт. Поставленный СОСЕДОМ скроллвью, он не видит ничего, и progress остаётся нулём — молча.

    menu_baseline