What you’ll learn
- Как работает механизм разметки Flutter.
- Как выложить виджеты вертикально и горизонтально.
- Как построить макет Flutter.
Это руководство по созданию макетов во Флаттере. В данной статье мы создадим макет для следующего приложения:
Это руководство делает детальный обзор темы макетов, чтобы объяснить подход Flutter к использованию макетов, и показывает, как разместить простой виджет на экране. После обсуждения способов размещения виджетов по горизонтали и вертикали рассматриваются некоторые из наиболее распространенных виджетов макета.
Шаг 0. Создаем базовый код приложения
Убедитесь, что вы настроили свою среду, а затем выполните следующие действия:
- Создаем базовое приложение Flutter «Hello World».
- Изменяем заголовок панели приложения и заголовок приложения следующим образом:
@override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Center( child: Text('Hello World'),
Шаг 1. Диаграмма макета
Первый шаг — разбить макет до его основных элементов:
- Определите строки и столбцы.
- В макете есть сетка?
- Есть ли перекрывающиеся элементы?
- Нужен ли вкладке пользовательский интерфейс?
- Обратите внимание на области, которые требуют выравнивания, заполнения или границы.
Сначала определите более крупные элементы. В этом примере четыре элемента расположены в столбце: изображение, две строки и блок текста.
Далее, схема каждого ряда. Первая строка, называемая разделом «Заголовок», имеет 3 дочерних элементов: столбец текста, значок звезды и номер. Его первый дочерний элемент, столбец, содержит 2 строки текста. Этот первый столбец занимает много места, поэтому его необходимо обернуть в Expanded виджет.
Вторая строка, называемая разделом «Кнопка», также имеет 3 дочерних элементов: каждый дочерний элемент представляет собой столбец, содержащий значок и текст.
После того, как макет был составлен, проще всего применить подход снизу вверх для его реализации. Чтобы свести к минимуму визуальную путаницу глубоко вложенного кода макета, поместите некоторые реализации в переменные и функции.
Шаг 2. Реализация строки заголовка
Сначала вы создадите левый столбец в разделе заголовка. Добавьте следующий код в начало метода build() класса MyApp:
Widget titleSection = Container( padding: const EdgeInsets.all(32), child: Row( children: [ Expanded( /*1*/ child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ /*2*/ Container( padding: const EdgeInsets.only(bottom: 8), child: Text( 'Oeschinen Lake Campground', style: TextStyle( fontWeight: FontWeight.bold, ), ), ), Text( 'Kandersteg, Switzerland', style: TextStyle( color: Colors.grey[500], ), ), ], ), ), /*3*/ Icon( Icons.star, color: Colors.red[500], ), Text('41'), ], ), );
/*1*/ — Помещение столбца в Expanded виджет, который растягивает столбец, чтобы использовать все оставшееся свободное место в строке. Установка свойства crossAxisAlignment в CrossAxisAlignment.start позиционирует столбец в начале строки.
/*2*/ — Помещение первой строки текста в контейнер Container позволяет вам добавлять отступы. Второй дочерний элемент в столбце, также текст, отображается серым цветом.
/*3*/ — Последние два элемента в строке заголовка — это значок звезды, окрашенный в красный цвет, и текст «41». Вся строка находится в контейнере и дополняется по каждому краю на 32 пикселя.
Добавьте раздел заголовка в тело приложения следующим образом:
... return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: Column( children: [ titleSection, ], ), ), ); ...
[info]Совет: при вставке кода в ваше приложение отступы могут искажаться. Вы можете исправить это в редакторе Flutter, используя поддержку автоматического переформатирования. Для ускорения процесса разработки воспользуйтесь функцией горячей перезагрузки Flutter. Если у вас есть проблемы, сравните ваш код с lib/main.dart.[/info]
Шаг 3: Реализация ряда кнопок
Секция кнопок содержит 3 столбца с одинаковым макетом — значок над строкой текста. Столбцы в этом ряду расположены равномерно, а текст и значки окрашены в основной цвет.
Поскольку код для построения каждого столбца практически идентичен, создайте частный вспомогательный метод с именем buildButtonColumn(), который принимает цвет, значок и текст и возвращает столбец с виджетами, окрашенными в заданный цвет.
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // ··· } Column _buildButtonColumn(Color color, IconData icon, String label) { return Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(icon, color: color), Container( margin: const EdgeInsets.only(top: 8), child: Text( label, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: color, ), ), ), ], ); } }
Функция добавляет значок прямо в столбец. Текст находится внутри контейнера с полем только для верхней части, отделяя текст от значка.
Создайте строку, содержащую эти столбцы, вызвав функцию и передав цвет, значок Icon и текст, относящиеся к этому столбцу. Выровняйте столбцы вдоль главной оси, используя MainAxisAlignment.spaceEvenly, чтобы равномерно распределить свободное пространство до, между и после каждого столбца. Добавьте следующий код чуть ниже объявления titleSection внутри метода build():
Color color = Theme.of(context).primaryColor; Widget buttonSection = Container( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildButtonColumn(color, Icons.call, 'CALL'), _buildButtonColumn(color, Icons.near_me, 'ROUTE'), _buildButtonColumn(color, Icons.share, 'SHARE'), ], ), );
Добавьте раздел кнопки в тело:
... return MaterialApp( title: 'Flutter layout demo', home: Scaffold( body: Column( children: [ titleSection, buttonSection, ], ), ), ); ...
Шаг 4: Реализация текстового раздела
Определите текстовый раздел как переменную. Поместите текст в контейнер и добавьте отступы вдоль каждого края. Добавьте следующий код чуть ниже объявления buttonSection:
Widget textSection = Container( padding: const EdgeInsets.all(32), child: Text( 'Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese ' 'Alps. Situated 1,578 meters above sea level, it is one of the ' 'larger Alpine Lakes. A gondola ride from Kandersteg, followed by a ' 'half-hour walk through pastures and pine forest, leads you to the ' 'lake, which warms to 20 degrees Celsius in the summer. Activities ' 'enjoyed here include rowing, and riding the summer toboggan run.', softWrap: true, ), );
Если для softwrap задано значение true, строки текста будут заполнять ширину столбца перед переносом по границе слова.
Добавьте текстовый раздел к телу:
... return MaterialApp( title: 'Flutter layout demo', home: Scaffold( children: [ titleSection, buttonSection, textSection, ], ), ), ...
Шаг 5: Реализация раздела изображения
Три из четырех элементов столбца теперь завершены, оставляя только изображение. Добавьте файл изображения к примеру:
- Создайте каталог изображений images в верхней части проекта.
- Добавить lake.jpg.
- Обновите файл pubspec.yaml, включив в него тег assets. Это делает изображение доступным для вашего кода.
... flutter: uses-material-design: true assets: - images/lake.jpg ...
[info] Обратите внимание, что wget не работает для сохранения этого двоичного файла. Исходное изображение доступно в Интернете по лицензии Creative Commons, но оно большое и медленно загружается. [/info]
Теперь вы можете ссылаться на изображение из вашего кода:
... ), body: Column( children: [ Image.asset( 'images/lake.jpg', width: 600, height: 240, fit: BoxFit.cover, ), titleSection, buttonSection, textSection, ...
BoxFit.cover сообщает фреймворку, что изображение должно быть как можно меньше, но должно охватывать весь блок визуализации.
Шаг 6: Последний штрих
На этом последнем шаге расположите все элементы в ListView, а не в Column, потому что ListView поддерживает прокрутку тела приложения, когда приложение запускается на небольшом устройстве.
... return MaterialApp( title: 'Flutter layout demo', home: Scaffold( appBar: AppBar( title: Text('Flutter layout demo'), ), body: ListView( children: [ Image.asset( 'images/lake.jpg', width: 600, height: 240, fit: BoxFit.cover, ...
Dart код:main.dart
Картинки:images
Файл pubspec:pubspec.yaml
Это оно! Когда вы перезагрузите приложение в горячем режиме, вы увидите тот же макет приложения, что и на скриншоте вверху этой страницы.
Вы можете добавить интерактивность к этому макету, следуя Adding Interactivity to Your Flutter App.