Ответ
В Flutter адаптивная и отзывчивая вёрстка — это подход к проектированию пользовательского интерфейса, при котором приложение корректно отображается и удобно используется на устройствах с разными размерами экранов (от маленького телефона до большого планшета или десктопа) и ориентациями.
Основные инструменты и техники:
-
MediaQuery— для получения характеристик экрана.final mediaData = MediaQuery.of(context); final screenWidth = mediaData.size.width; final screenHeight = mediaData.size.height; final pixelRatio = mediaData.devicePixelRatio; final isPortrait = screenHeight > screenWidth; -
LayoutBuilder— для реагирования на размеры родительского виджета. Более предпочтителен, чемMediaQuery, когда виджет должен адаптироваться к доступному пространству, а не ко всему экрану.LayoutBuilder( builder: (context, constraints) { // constraints.maxWidth — максимальная доступная ширина if (constraints.maxWidth > 600) { return _buildWideLayout(); // Макет для планшета/десктопа } else { return _buildNarrowLayout(); // Макет для телефона } }, ) -
Использование гибких виджетов (
Flexible,Expanded) внутриRowиColumn.Row( children: [ Expanded( // Занимает всё оставшееся пространство flex: 2, child: Container(color: Colors.red), ), Expanded( flex: 1, child: Container(color: Colors.blue), ), ], ) -
OrientationBuilder— для реакции на изменение ориентации.OrientationBuilder( builder: (context, orientation) { return orientation == Orientation.portrait ? _buildPortraitScaffold() : _buildLandscapeScaffold(); }, ) -
Определение брейкпоинтов (breakpoints) для разных категорий устройств.
class Breakpoints { static const double mobile = 600; // До 600px — телефон static const double tablet = 900; // 600-900px — планшет // >900px — десктоп } // Использование if (screenWidth < Breakpoints.mobile) { // Мобильный UI } else if (screenWidth < Breakpoints.tablet) { // Планшетный UI } else { // Десктопный UI }
Практический пример: адаптивный список деталей (master-detail):
class AdaptiveDetailPage extends StatelessWidget {
final Widget masterView;
final Widget detailView;
const AdaptiveDetailPage({
super.key,
required this.masterView,
required this.detailView,
});
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
// На широком экране показываем master и detail рядом
if (screenWidth > 600) {
return Row(
children: [
SizedBox(width: 300, child: masterView),
Expanded(child: detailView),
],
);
}
// На узком экране используем навигацию между экранами
else {
return masterView; // При тапе на элемент открываем detailView на новом экране
}
}
}
Ключевые принципы:
- Относительные единицы: Использовать
FractionallySizedBox, проценты,flexвместо фиксированных пикселей. - Тестирование: Обязательно тестировать UI на эмуляторах/устройствах с разными диагоналями и плотностями пикселей.
- Содержание прежде всего: Макет должен адаптироваться, чтобы контент оставался читаемым и доступным.
Ответ 18+ 🔞
Э, слушай, тут про адаптивную вёрстку во Flutter. Ну, типа, чтобы твоё приложение не выглядело как хуй в пальто — на телефоне одно, а на планшете всё плывёт и кнопку "купить" надо искать лупой, блядь.
Основные штуки, без которых нихуя не получится:
-
MediaQuery— это как спросить у телефона: "А ты кто такой, ёпта?" Ты узнаёшь размер экрана, плотность пикселей — всю подноготную. Без этого как слепой кот — будешь на ощупь верстать.final mediaData = MediaQuery.of(context); final screenWidth = mediaData.size.width; // Узнал ширину final screenHeight = mediaData.size.height; // Узнал высоту // И теперь можешь думать, что куда впихнуть. -
LayoutBuilder— а это поумнее будет. Он смотрит не на весь экран, а на то пространство, которое ему родитель выделил. Овердохуища полезная штука, когда у тебя не весь экран занят, а только кусок.LayoutBuilder( builder: (context, constraints) { // constraints.maxWidth — вот столько места есть, не больше. if (constraints.maxWidth > 600) { return _buildWideLayout(); // Развернулся на полную, планшетный режим } else { return _buildNarrowLayout(); // Скромно, по-мобильному } }, ) -
Гибкие виджеты (
Flexible,Expanded). Это чтобы не делить пиксели вручную, как последний распиздяй. Сказал "расширяйся" — и они сами поделили оставшееся место. Красота, ебать.Row( children: [ Expanded( // Этот жадный — заберёт 2 доли из трёх flex: 2, child: Container(color: Colors.red), ), Expanded( // А этому одна доля достанется flex: 1, child: Container(color: Colors.blue), ), ], ) -
OrientationBuilder— чувак, который понимает, что телефон повернули. Альбомная или портретная? Он скажет.OrientationBuilder( builder: (context, orientation) { return orientation == Orientation.portrait ? _buildPortraitScaffold() // Вертикально — одна верстка : _buildLandscapeScaffold(); // Горизонтально — другая }, ) -
Брейкпоинты. Это такие магические числа, после которых всё меняется. Типа, меньше 600 пикселей — это телефон, больше — уже можно планшетную раскладку городить. Главное — не наделать их овердохуища, а то запутаешься, как собака сука.
class Breakpoints { static const double mobile = 600; static const double tablet = 900; } // Использование if (screenWidth < Breakpoints.mobile) { // Телефон, всё компактно } else if (screenWidth < Breakpoints.tablet) { // Планшет, можно пошире } else { // Десктоп, ёперный театр, разгоняйся на полную }
Пример из жизни: список и детали (master-detail). Вот где ад начинается, если не подумать об адаптивности. На телефоне показываем список, тапнул — открылась деталька на весь экран. На планшете надо сразу и список, и детали рядом показывать, ядрёна вошь!
class AdaptiveDetailPage extends StatelessWidget {
final Widget masterView; // Список
final Widget detailView; // Детали
const AdaptiveDetailPage({
super.key,
required this.masterView,
required this.detailView,
});
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
// Если экран широкий (планшет/десктоп) — вываливаем всё рядом
if (screenWidth > 600) {
return Row(
children: [
SizedBox(width: 300, child: masterView), // Список фиксированной ширины
Expanded(child: detailView), // Детали занимают всё остальное
],
);
}
// Если экран узкий (телефон) — показываем только список, детали будут в новом окне
else {
return masterView;
}
}
}
Главные правила, которые надо вбить себе в башку:
- Не пиши фиксированные размеры, как последний бздун. Используй проценты,
flex,FractionallySizedBox. Мир не состоит из iPhone 13 Pro Max. - Тестируй, блядь, на всём! От самого мелкого пылесоса-телефона до огромного планшета. И поворачивай экран, а то выйдет хитрая жопа, которая только в портрете работает.
- Контент — главный. Адаптивность — это не ради прикола. Это чтобы текст можно было прочитать, а кнопку — нажать, а не промазать мимо пальцем. Если для этого надо всё перелопатить — перелопачивай. Иначе доверия ебать ноль у пользователей будет.
Видео-ответы
▶
▶
▶
▶
▶