В чем смысл?
- Виджеты — это классы, используемые для создания пользовательского интерфейса.
- Виджеты используются как для элементов макета, так и для элементов пользовательского интерфейса.
- Составьте простые виджеты для построения сложных виджетов.
Ядром механизма макетов Flutter являются виджеты. В Flutter почти все является виджетами — даже модели макетов являются виджетами. Изображения, значки и текст, которые вы видите в приложении Flutter, являются виджетами. Все невидимые элементы — это также виджеты, например, строки, столбцы и сетки, которые упорядочивают, сжимают и выравнивают видимые виджеты.
Вы создаете макет путем компоновки виджетов для построения более сложных виджетов. Например, на первом скриншоте ниже показаны 3 значка с надписями под каждым из них:


На втором скриншоте отображается визуальный макет, показывающая строку из 3 столбцов, где каждый столбец содержит значок и надпись.
Примечание: Большинство скриншотов в этом руководстве отображаются с установленным в true значением debugPaintSizeEnabled, чтобы вы могли видеть визуальную раскладку. Дополнительные сведения см. в разделе Проблемы отладочной макетной компоновки в визуальном виде в разделе Использование инспектора Flutter.
Вот диаграмма дерева виджетов для этого пользовательского интерфейса:

Большая часть этого должна выглядеть так, как вы могли бы ожидать, но вас могут заинтересовать контейнеры (показаны розовым цветом). Container (контейнер) — это класс виджетов, который позволяет настраивать свои дочерние виджеты. Используйте Container (контейнер), когда вы хотите добавить внутренние отступы, поля, границы или цвет фона, чтобы обозначить некоторые из его характеристик.
В данном примере каждый Text (текстовый) виджет помещается в Container (контейнер) для добавления полей. Все Row (строки) также помещаются в Container, чтобы добавить внутренний отступ вокруг строки.
Остальная часть пользовательского интерфейса в этом примере контролируется свойствами. Установите цвет значка, используя его цветовое свойство color. Используйте свойство Text.style для установки шрифта, его цвета, ширины и так далее. Столбцы и строки имеют свойства, которые позволяют указать, как их дочерние элементы выровнены по вертикали или горизонтали, и сколько места должно занимать дочернее пространство.
Расположите виджет
Как расположить один виджет в Flutter? В этом разделе показано, как создать и отобразить простой виджет. Он также показывает весь код для простого приложения Hello World.
В Flutter, требуется всего несколько шагов, чтобы поместить на экран текст, иконку или изображение.
1.Выберите виджет макета
Выбирайте из множества виджетов макет в зависимости от того, как вы хотите выровнять или ограничить видимый виджет, так как эти характеристики обычно передаются содержащемуся в нем виджету.
В данном примере используется Center (центр), который центрирует содержимое по горизонтали и вертикали.
2. Создайте видимый виджет
Например, создайте Text (текстовый) виджет:
Text('Hello World'),
Создайте Image (изображение) виджет:
Image.asset(
'images/lake.jpg',
fit: BoxFit.cover,
),
Создайте виджет с иконкой Icon:
Icon(
Icons.star,
color: Colors.red[500],
),
3. Добавьте видимый виджет в виджет макета
Все виджеты макета имеют одно из следующих свойств:
- Свойство дочернего виджета child если берется один дочерний виджет — Center (центр) или Container (контейнер)
- Свойство дочерних виджетов children, если они берут список виджетов, например, Row (строка), Column (столбец), ListView (просмотр списка) , или Stack (стек).
Добавьте виджет Text (текст) в виджет Center (центр):
Center(
child: Text('Hello World'),
),
4. Добавьте виджет макета на страницу
Приложение Flutter само по себе является виджетами, и большинство виджетов имеют метод build(). При приведении и возврате виджета в метод build() приложения отображается виджет.
Приложения Material
Для приложения Material можно использовать виджет Scaffold; он предоставляет баннер по умолчанию, цвет фона, а также имеет API для добавления элементов оформления контейнеров, верхних меню и нижних меню кнопок. Затем можно добавить виджет Center (центр) непосредственно в свойство Body (тело) для главной страницы.
lib/main.dart (MyApp)
class MyApp extends StatelessWidget {
@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'),
),
),
);
}
}
Примечание: Библиотека Material реализует виджеты, которые следуют принципам Material Design. При проектировании пользовательского интерфейса можно использовать только виджеты из стандартной библиотеки виджетов или виджеты из библиотеки Material. Можно смешивать виджеты из обеих библиотек, настраивать существующие виджеты или создавать собственный набор пользовательских виджетов.
Приложения не Material
Для не-Material приложений можно добавить виджет Center в метод build() приложения:
lib/main.dart (MyApp)
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white),
child: Center(
child: Text(
'Hello World',
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 32,
color: Colors.black87,
),
),
),
);
}
}
По умолчанию не-Material приложение, не содержит AppBar (меню), заголовка или цвета фона. Если вы хотите, чтобы эти функции были доступны в не-Material приложении, вам необходимо собрать их самостоятельно. Это приложение меняет цвет фона на белый, а текст — на темно-серый, чтобы имитировать приложение Material.
Вот так! Когда вы запустите приложение, то должны увидеть «Hello World».

Исходный код приложения:
Разместите несколько виджетов вертикально и горизонтально
Одной из наиболее распространенных схем макета является расположение виджетов по вертикали или горизонтали. Виджет Row (строка) можно использовать для расположения виджетов по горизонтали, а виджет Column (столбец) — для расположения виджетов по вертикали.
В чем смысл?
- Row (строка) и Column (столбец) — два наиболее часто используемых шаблона макета.
- Row и Column каждый из них берет список дочерних child виджетов.
- Дочерний Child виджет может быть сам по себе виджет Row, Column или другой сложный виджет.
- Вы можете указать, как Row (строка) или Column (столбец) выравнивает свои дочерние виджеты как по вертикали, так и по горизонтали.
- Можно растягивать или ограничивать определенные дочерние Child виджеты.
- Вы можете указать, как дочерние виджеты используют доступное пространство строки или столбца.
Чтобы создать строку или столбец в Flutter, вы добавляете список Children (дочерних) виджетов в виджет «Row» или «Column». В свою очередь, каждый дочерний Child виджет может сам быть строкой или столбцом и так далее. Следующий пример показывает, как можно разместить строки или столбцы внутри строк или столбцов.
Эта разметка организована как Строка. Строка содержит два дочерних Children элементов: слева — столбец, справа — изображение:

Дерево виджетов левого столбца содержит строки и столбцы.

Вы реализуете код макета Павловой в строках и столбцах вложенности.
Примечание: Row и Column - базовые примитивные виджеты для горизонтальной и вертикальной компоновки - эти низкоуровневые виджеты обеспечивают максимальную настройку. Flutter также предлагает специализированные виджеты более высокого уровня, которые могут быть достаточны для ваших нужд. Например, вместо Row вы можете предпочесть ListTile, простой в использовании виджет со свойствами для ведущей и скользящей иконки, и до 3 строк текста. Вместо Column вы можете предпочесть ListView, компоновку, похожую на колонку, которая автоматически прокручивается, если ее содержимое слишком длинное, чтобы уместить его в доступном пространстве. Дополнительные сведения см. в разделе Общие виджеты макета.
Выравнивание виджетов
Вы управляете выравниванием дочерних элементов строки или столбца с помощью свойств mainAxisAlignment (выравнивание по главной оси) и crossAxisAlignment (выравнивание по поперечной оси). Для строки главная ось работает горизонтально, а поперечная — вертикально. В случае столбца главная ось работает вертикально, а поперечная ось — горизонтально.


Классы MainAxisAlignment и CrossAxisAlignment предлагают различные константы для управления выравниванием.
Примечание: Когда вы добавляете изображения в свой проект, вам нужно обновить файл pubspec.yaml для доступа к ним - этот пример использует Image.asset для отображения изображений. Для получения дополнительной информации смотрите файл pubspec.yaml в этом примере или Добавление вложений и изображений. Вам не нужно делать этого, если вы ссылаетесь на онлайн-образы, используя Image.network.
В следующем примере каждое из 3-х изображений имеет ширину 100 пикселей. Окно рендера (в данном случае весь экран) имеет ширину более 300 пикселей, поэтому установка выравнивания по главной оси на SpaceEvenly (равномерное пространство) равномерно делит свободное горизонтальное пространство между, до и после каждого изображения.
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);

Источник приложения: row_column
Колонки работают так же, как и строки. В следующем примере показан столбец из 3-х изображений, каждое из которых имеет высоту 100 пикселей. Высота окна рендера (в данном случае всего экрана) составляет более 300 пикселей, поэтому установка выравнивания по главной оси на SpaceEvenly (равномерное пространство) равномерно разделяет свободное вертикальное пространство между, над и под каждым изображением.
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('images/pic1.jpg'),
Image.asset('images/pic2.jpg'),
Image.asset('images/pic3.jpg'),
],
);

Источник приложения: row_column
Виджеты для измерения размеров
Когда макет слишком велик, чтобы подойти к устройству, вдоль затронутого края появляется желто-черная полоска. Вот пример слишком широкой полосы:

Виджеты могут иметь размер, соответствующий размеру строки или столбца, с помощью виджета Expanded (расширенный). Чтобы исправить предыдущий пример, когда ряд изображений слишком широк для его рендеринга, оберните каждое изображение Expanded виджетами.
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);

Источник приложения: sizing
Возможно, вы хотите, чтобы виджет занимал вдвое больше места, чем другие дочерние виджеты. Для этого используйте свойство Expanded виджета flex, целое число, определяющее коэффициент гибкости для виджета. По умолчанию коэффициент гибкости равен 1. Следующий код устанавливает коэффициент гибкости среднего изображения равным 2:
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Image.asset('images/pic1.jpg'),
),
Expanded(
flex: 2,
child: Image.asset('images/pic2.jpg'),
),
Expanded(
child: Image.asset('images/pic3.jpg'),
),
],
);

Источник приложения: sizing
Виджеты для упаковки
По умолчанию строка или столбец занимает как можно больше места вдоль своей главной оси, но если вы хотите упаковать дочерние виджеты близко друг к другу, установите mainAxisSize в MainAxisSize.min. В следующем примере это свойство используется для упаковки значков звезд вместе.
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
)

Источник приложения: pavlova
Вложенные строки и столбцы
Макет фреймворка позволяет вложить строки и столбцы внутри строк и столбцов настолько глубоко, насколько это необходимо. Рассмотрим код выделенного участка следующего макета:

Выделенный раздел выполнен в два ряда. Строка рейтингов содержит пять звезд и количество отзывов. Строка значков содержит три столбца значков и текста.
Дерево виджетов для строки рейтингов:

Переменная рейтингов создает строку, содержащую меньшую строку из 5-звездочных значков и текста:
var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
);
final ratings = Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);
Совет: чтобы свести к минимуму визуальную путаницу, которая может возникнуть из-за сильно вложенного кода макета, введите фрагменты пользовательского интерфейса в переменные и функции.
Строка значков под строкой рейтингов содержит 3 столбца; каждый столбец содержит значок и две строки текста, как видно из дерева виджетов:

Переменная iconList определяет строку значков:
final descTextStyle = TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 18,
height: 2,
);
// DefaultTextStyle.merge() allows you to create a default text
// style that is inherited by its child and all subsequent children.
final iconList = DefaultTextStyle.merge(
style: descTextStyle,
child: Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.kitchen, color: Colors.green[500]),
Text('PREP:'),
Text('25 min'),
],
),
Column(
children: [
Icon(Icons.timer, color: Colors.green[500]),
Text('COOK:'),
Text('1 hr'),
],
),
Column(
children: [
Icon(Icons.restaurant, color: Colors.green[500]),
Text('FEEDS:'),
Text('4-6'),
],
),
],
),
),
);
Переменная leftColumn (левый столбец) содержит строки рейтингов и значков, а также заголовок и текст, описывающий Павлову:
final leftColumn = Container(
padding: EdgeInsets.fromLTRB(20, 30, 20, 20),
child: Column(
children: [
titleText,
subTitle,
ratings,
iconList,
],
),
);
Левый столбец помещается в Container (контейнер) для ограничения его ширины. Наконец, пользовательский интерфейс строится всем рядом (содержащим левый столбец и изображение) внутри Card (карты).
Изображение Павловой из Pixabay. Вы можете встраивать изображение из сети с помощью Image.network(), но, например, в этом примере, изображение сохраняется в каталог изображений в проекте, добавляется в файл pubspec, и доступ к нему осуществляется с помощью Images.asset(). Дополнительную информацию см. в разделе Добавление средств и изображений.
body: Center(
child: Container(
margin: EdgeInsets.fromLTRB(0, 40, 0, 30),
height: 600,
child: Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 440,
child: leftColumn,
),
mainImage,
],
),
),
),
),
Совет: Пример с Павловой лучше всего работает по горизонтали на широком устройстве, например, планшете. Если вы запускаете этот пример в симуляторе iOS, вы можете выбрать другое устройство с помощью меню Оборудование > Устройство. Для этого примера мы рекомендуем iPad Pro. Вы можете изменить его ориентацию в горизонтальном режиме с помощью Оборудование > Поворот. Вы также можете изменить размер окна симулятора (без изменения количества логических пикселей) с помощью меню Окно > Масштаб.
Источник приложения: pavlova
Общие виджеты макета
Flutter имеет богатую библиотеку виджетов верстки. Вот несколько наиболее часто используемых. Цель состоит в том, чтобы как можно быстрее привести вас в рабочее состояние, а не перегружать полным списком. Для получения информации о других доступных виджетах обратитесь к каталогу Виджетов или используйте окно Поиск в справочной документации API. Кроме того, на страницах виджетов в документах API часто содержатся предложения о похожих виджетах, которые лучше всего подходят для ваших нужд.
Следующие виджеты делятся на две категории: стандартные виджеты из библиотеки виджетов и специализированные виджеты из библиотеки Material. Любое приложение может использовать библиотеку виджетов, но только приложения » Material » могут использовать библиотеку «Material Components»
Стандартные виджеты
- Container (контейнер): Добавляет в виджет отступы, поля, границы, цвет фона или другие украшения.
- GridView (сетка): Размещает виджеты в виде прокручиваемой сетки.
- ListView (список): Размещает виджеты в виде прокручиваемого списка.
- Stack: (набор) Накладывает виджет на другой.
Виджеты Material
- Card (карточка): Организует необходимую информацию в блок (карточку) с закругленными углами и тенью от падения.
- ListTile (список-плитка): Организует до 3 строк текста, а также опционально ведущие и задние значки в строку.
Container
Во многих макетах контейнеры свободно используются для разделения виджетов с помощью отступов или добавления границ или полей. Вы можете изменить фон устройства, поместив весь макет в Container и изменив цвет его фона или изображение.
Резюме (Container)
- Добавляет отступы, поля, границы
- Изменяет цвет фона или изображение
- Содержит один дочерний виджет, но этот виджет может быть Row, Column или даже корнем дерева виджетов.

Примеры (Container)
Этот макет состоит из столбца с двумя строками, каждая из которых содержит 2 изображения. Container используется для изменения цвета фона столбца на более светло-серый.
Widget _buildImageColumn() => Container(
decoration: BoxDecoration(
color: Colors.black26,
),
child: Column(
children: [
_buildImageRow(1),
_buildImageRow(3),
],
),
);

Container также используется для добавления закругленной границы и полей к каждому изображению:
Widget _buildDecoratedImage(int imageIndex) => Expanded(
child: Container(
decoration: BoxDecoration(
border: Border.all(width: 10, color: Colors.black38),
borderRadius: const BorderRadius.all(const Radius.circular(8)),
),
margin: const EdgeInsets.all(4),
child: Image.asset('images/pic$imageIndex.jpg'),
),
);
Widget _buildImageRow(int imageIndex) => Row(
children: [
_buildDecoratedImage(imageIndex),
_buildDecoratedImage(imageIndex + 1),
],
);
GridView
Используйте GridView, чтобы выложить виджеты в виде двухстороннего списка. GridView предоставляет два готовых списка, или вы можете построить свою собственную пользовательскую сетку. Когда GridView обнаруживает, что его содержимое слишком длинное, чтобы поместиться в поле рендеринга, он автоматически прокручивается.
Резюме (GridView)
- Выкладывает виджеты в сетку
- Обнаруживает, когда содержимое столбца выходит за пределы области рендеринга, и автоматически обеспечивает прокрутку
- Создает свою собственную сетку или использует одну из предоставленных сеток:
- GridView.count позволяет указать количество столбцов
- GridView.extent позволяет задать максимальную ширину плитки в пикселях.
Примечание: При отображении двустороннего списка, где важно, какую строку и столбец занимает клетка (например, это запись в столбце "калорийность" для строки "авокадо"), используйте Table или DataTable.
Примеры (GridView)

Используйте GridView.count для создания сетки шириной 2 плитки в портретном режиме и 3 плитки в ландшафтном режиме. Заголовки создаются путем установки свойства footer для каждого GridTile.
Dart code: grid_list_demo.dart из галереи Flutter Gallery

Используйте GridView.extent для создания сетки с плитками шириной не более 150 пикселей.
Источник приложения: grid_and_list
Widget _buildGrid() => GridView.extent(
maxCrossAxisExtent: 150,
padding: const EdgeInsets.all(4),
mainAxisSpacing: 4,
crossAxisSpacing: 4,
children: _buildGridTileList(30));
// The images are saved with names pic0.jpg, pic1.jpg...pic29.jpg.
// The List.generate() constructor allows an easy way to create
// a list when objects have a predictable naming pattern.
List<Container> _buildGridTileList(int count) => List.generate(
count, (i) => Container(child: Image.asset('images/pic$i.jpg')));
ListView
ListView, виджет, похожий на колонку, автоматически обеспечивает прокрутку, когда его содержимое слишком длинное для его рендеринга.
Резюме (ListView)
- Специализированная колонка для организации списка боксов
- Может быть расположен горизонтально или вертикально
- Обнаруживает, когда его содержимое не помещается, и обеспечивает прокрутку.
- Менее настраиваемый, чем колонка, но более простой в использовании и поддерживающий прокрутку.
Примеры (ListView)

Используйте ListView для отображения списка компаний с помощью ListTiles. Делитель отделяет театры от ресторанов.
Источник приложения: grid_and_list

Используйте ListView для отображения цветов из Material Design palette для определенного семейства цветов.
Dart code: colors_demo.dart из галереи Flutter Gallery
Widget _buildList() => ListView(
children: [
_tile('CineArts at the Empire', '85 W Portal Ave', Icons.theaters),
_tile('The Castro Theater', '429 Castro St', Icons.theaters),
_tile('Alamo Drafthouse Cinema', '2550 Mission St', Icons.theaters),
_tile('Roxie Theater', '3117 16th St', Icons.theaters),
_tile('United Artists Stonestown Twin', '501 Buckingham Way',
Icons.theaters),
_tile('AMC Metreon 16', '135 4th St #3000', Icons.theaters),
Divider(),
_tile('K\'s Kitchen', '757 Monterey Blvd', Icons.restaurant),
_tile('Emmy\'s Restaurant', '1923 Ocean Ave', Icons.restaurant),
_tile(
'Chaiya Thai Restaurant', '272 Claremont Blvd', Icons.restaurant),
_tile('La Ciccia', '291 30th St', Icons.restaurant),
],
);
ListTile _tile(String title, String subtitle, IconData icon) => ListTile(
title: Text(title,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
Stack
Используйте Stack, чтобы расположить виджеты поверх базового виджета — часто изображение. Виджеты могут полностью или частично перекрывать базовый виджет.
Резюме (Stack)
- Использует для виджетов, которые перекрывают другой виджет.
- Первый виджет в списке дочерних элементов — это базовый виджет; последующие дочерние элементы накладываются поверх этого базового виджета.
- Содержимое Stack не может прокручиваться.
- Вы можете выбрать клип дочерних виджетов, которые превышают окно рендеринга
Примеры (Stack)

Используйте Stack для наложения Container (текст которого отображается на полупрозрачном черном фоне) на верхнюю часть CircleAvatar. Stack сбивает текст, используя свойство выравнивания Alignment.
Источник приложения: card_and_stack

Используйте Stack для наложения градиента на верхнюю часть изображения. Градиент обеспечивает четкое разделение значков панели инструментов по отношению к изображению.
Dart code: contacts_demo.dart из галереи Flutter Gallery
Widget _buildStack() => Stack(
alignment: const Alignment(0.6, 0.6),
children: [
CircleAvatar(
backgroundImage: AssetImage('images/pic.jpg'),
radius: 100,
),
Container(
decoration: BoxDecoration(
color: Colors.black45,
),
child: Text(
'Mia B',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
);
Card
Карточка Card из Material library содержит сопутствующие самородки информации и может быть составлена практически из любого виджета, но часто используется со списком ListTile. Card имеет единственный дочерний элемент, но это может быть столбец, строка, список, сетка или другой виджет, поддерживающий несколько дочерних элементов. По умолчанию размер Card уменьшается до 0 на 0 пикселей. Вы можете использовать SizeBox для ограничения размера Card.
В Flutter, Card имеет слегка закругленные углы и тень от капли, что придает ей 3D эффект. Изменение свойства высоты Card позволяет управлять эффектом отбрасываемой тени. Установка значения высоты на 24, например, визуально поднимает Card дальше от поверхности и вызывает рассеивание тени. Список поддерживаемых значений высоты см. в Руководстве по материалам «Высота». При указании неподдерживаемого значения тень отбрасывания отключается полностью.
Резюме (Card)
- Встраивается в Material карточку
- Используется для представления соответствующих кусков информации
- Принимает один дочерний элемент, но этот дочерний элемент может быть Row (строка), Column (столбец) или другим видом, который содержит список дочерних элементов.
- Отображается со скругленными углами и каплевидной тенью
- Содержимое Card не может прокручиваться.
- Из библиотеки Material
Примеры (Card)

Card (карточка), содержащая 3 плитки ListTiles и размером с SizeBox. Делитель Divider разделяет первую и вторую плитку ListTiles.
Источник: card_and_stack

Card, содержащая изображение и текст.
Dart код: cards_demo.dart из Flutter галереи
Widget _buildCard() => SizedBox(
height: 210,
child: Card(
child: Column(
children: [
ListTile(
title: Text('1625 Main Street',
style: TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text('My City, CA 99984'),
leading: Icon(
Icons.restaurant_menu,
color: Colors.blue[500],
),
),
Divider(),
ListTile(
title: Text('(408) 555-1212',
style: TextStyle(fontWeight: FontWeight.w500)),
leading: Icon(
Icons.contact_phone,
color: Colors.blue[500],
),
),
ListTile(
title: Text('costa@example.com'),
leading: Icon(
Icons.contact_mail,
color: Colors.blue[500],
),
),
],
),
),
);
ListTile
Используйте ListTile (список плиток), специализированный виджет строк из библиотеки Material, для простого способа создания строки, содержащей до 3 строк текста и опциональных ведущих и следующих значков . ListTile чаще всего используется в Card или ListView, но может использоваться и в других местах.
Резюме (ListTile)
- Специализированная строка, содержащая до 3 строк текста и дополнительные иконки
- Менее настраиваемый, чем Row, но более простой в использовании.
- Из библиотеки Material
Примеры (ListTile)

Карточка Card, содержащая 3 плитки ListTiles.
Источник: card_and_stack

Использует ListTile для перечисления 3 типов выпадающих кнопок.
Dart код: buttons_demo.dart из галереи Flutter Gallery
Ограничения
Чтобы полностью понять систему макетов Flutter, вам необходимо узнать, как Flutter позиционирует и размещает компоненты в макетах. Для получения дополнительной информации см. раздел «Понимание ограничений«.