Управляемая вёрстка под устройства разных размеров

2022-10-30

При разработке мобильных приложений может потребоваться учитывать размеры устройства - вёрстка для планшета и смартфона часто отличается. При этом, как правило, поначалу у нас есть вёрстка только под один тп устройства (mobile), а с развитием продукта появляется необходимость уникальной вёрстки для планшетов, а с недавних пор и сворачиваемых устройств (foldable). Кроме того, если ваше приложение поддерживает веб или десктоп, то изменение размеров окна становится типичным сценарием.

Итак, нам необходимо решение, которое позволяет:

  • гибко управлять вёрсткой для разных размеров экрана;
  • постепенно внедрять поддержку новых форм-факторов;
  • реагирует на изменение размеров окна (веб и десктоп).

Для этого нам потребуется виджет следующего вида:

class DeviceLayoutBuilder extends StatelessWidget {
  final WidgetBuilder mobile;
  final WidgetBuilder foldable;
  final WidgetBuilder tablet;

  const DeviceLayoutBuilder({
    super.key,
    required this.mobile,
    required this.foldable,
    required this.tablet,
  });

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size.shortestSide;

    if (size > 840) return tablet(context);
    if (size > 600) return foldable(context);

    return mobile(context);
  }
}

В данном случае у нас две контрольные точки размеров, которые "разделяют" вёрстку на три форм-фактора - обычное мобильное устройство, устройство в форм-факторе fold и планшет.

При желании легко можно увеличить количество контрольных точек или изменить их значение.

Как использовать?

Типичный пример использования выглядит следующим образом:

class MyScreen extends StatelessWidget {
  const MyScreen({super.key});

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(),
        body: DeviceLayoutBuilder(
          mobile: (_) => MyMobileContent(),
          foldable: (_) => MyFoldableContent(),
          tablet: (_) => MyTabletContent(),
        ),
      );
}

Здесь MyMobileContent, MyFoldableContent и MyTabletContent - виджеты, реализующие вёрстку для соответствующего форм-фактора.

Само собой, если на текущий момент у вас нет реализации для какого-то форма-фактора, то можно использовать имеющийся и заменить его на нужный, когда он будет готов:

DeviceLayoutBuilder(
  mobile: (_) => MyMobileContent(),
  foldable: (_) => MyMobileContent(),
  tablet: (_) => MyTabletContent(),
)