1. Введение
| Компоненты Material Design (MDC) помогают разработчикам реализовывать принципы Material Design. MDC, созданный командой инженеров и UX-дизайнеров Google, содержит десятки красивых и функциональных компонентов интерфейса и доступен для Android, iOS, интернета и Flutter.material.io/develop |
Теперь вы можете использовать Material Flutter, чтобы настраивать уникальный стиль своих приложений. Недавнее расширение Material Design дало дизайнерам и разработчикам больше возможностей для выражения бренда продукта.
В практических работах MDC-101 и MDC-102 вы использовали Material Flutter,чтобы создать основу приложения Shrine – платформы для электронной торговли, на которой продаются одежда и товары для дома. В этом приложении пользователь сначала попадает на экран входа, а затем на главный экран с товарами.
Что вы создадите
В этой практической работе вы настроите приложение Shrine, используя:
- Цвет
- Типографика
- Высота
- Фигура
- Макет
Android | iOS |
|
|
|
|
Компоненты и подсистемы Material Design для Flutter, используемые в этой практической работе
- Темы
- Типографика
- Высота
- Список изображений
Как бы вы оценили свой уровень опыта разработки с помощью Flutter?
2. Как настроить среду разработки Flutter
Для выполнения этого практического занятия вам понадобятся два компонента: Flutter SDK и редактор.
Вы можете выполнить практическую работу на любом из этих устройств:
- Физическое устройство Android или iOS, подключенное к компьютеру и настроенное на режим разработчика.
- Симулятор iOS (требуется установить инструменты Xcode).
- Эмулятор Android (требуется настройка в Android Studio).
- Браузер (для отладки требуется Chrome).
- В виде приложения для компьютеров с ОС Windows, Linux или macOS. Разработку нужно вести на той платформе, на которой вы планируете развертывание. Поэтому, если вы хотите разработать компьютерное приложение для Windows, вам нужно делать это на компьютере с Windows, чтобы получить доступ к подходящей цепочке сборки. Требования к операционной системе подробно описаны на сайте docs.flutter.dev/desktop.
3. Скачайте стартовое приложение для практической работы
Продолжаете изучать MDC-102?
Если вы выполнили практическую работу MDC-102, ваш код должен быть готов к использованию в этой работе. Перейдите к шагу Измените цвета.
Начинаете с нуля?
Скачайте начальное приложение для практической работы
Стартовое приложение находится в каталоге material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series.
...или клонировать его с GitHub
Чтобы клонировать эту практическую работу из GitHub, выполните следующие команды:
git clone https://github.com/material-components/material-components-flutter-codelabs.git cd material-components-flutter-codelabs/mdc_100_series git checkout 103-starter_and_102-complete
Как открыть проект и запустить приложение
- Откройте проект в любом редакторе.
- Следуйте инструкциям в разделе "Запустите приложение" статьи Начало работы: пробный запуск для выбранного редактора.
Готово! На устройстве должна появиться страница входа в Shrine из предыдущей лабораторной работы.
Android | iOS |
|
|
Нажмите "Далее", чтобы перейти на страницу товара.
Android | iOS |
|
|
4. Как изменить цвета
Цветовая схема, представляющая бренд Shrine, создана, и дизайнер хочет, чтобы вы реализовали эту цветовую схему в приложении Shrine.
Для начала давайте импортируем эти цвета в наш проект.
Создать colors.dart
Создай новый файл Dart в lib с названием colors.dart. Импортируйте material.dart и добавьте значения const Color:
import 'package:flutter/material.dart';
const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);
const kShrineBrown900 = Color(0xFF442B2D);
const kShrineErrorRed = Color(0xFFC5032B);
const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;
Пользовательская цветовая палитра
Эта цветовая тема создана дизайнером с использованием пользовательских цветов (показаны на изображении ниже). В нем содержатся цвета, выбранные из бренда Shrine и примененные к редактору тем Material, который расширил их, чтобы создать более полную палитру. (Эти цвета не относятся к цветовым палитрам Material 2014 года.)
В редакторе тем Material они упорядочены по оттенкам, которые обозначены числами от 50 до 900 с шагом 100. Shrine использует только оттенки 50, 100 и 300 из розового образца и 900 из коричневого образца.

Каждый цветной параметр виджета сопоставлен с цветом из этих схем. Например, цвет декораций текстового поля, когда оно активно принимает ввод, должен быть основным цветом темы. Если этот цвет плохо виден на фоне, используйте другой.
Теперь, когда мы выбрали цвета, которые хотим использовать, мы можем применить их к интерфейсу. Для этого мы зададим значения виджета ThemeData, который применим к экземпляру MaterialApp в верхней части иерархии виджетов.
Настройка ThemeData.light()
Во Flutter есть несколько встроенных тем. Светлая тема – одна из них. Вместо того чтобы создавать виджет ThemeData с нуля, мы скопируем светлую тему и изменим значения, чтобы настроить ее для нашего приложения.
Импортируйте colors.dart в app.dart.
import 'colors.dart';
Затем добавьте в файл app.dart следующий код за пределами класса ShrineApp:
// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light(useMaterial3: true);
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: kShrinePink100,
onPrimary: kShrineBrown900,
secondary: kShrineBrown900,
error: kShrineErrorRed,
),
// TODO: Add the text themes (103)
// TODO: Decorate the inputs (103)
);
}
Теперь задайте для параметра theme: в конце функции build() приложения ShrineApp (в виджете MaterialApp) новую тему:
// TODO: Customize the theme (103)
theme: _kShrineTheme, // New code
Сохранить проект. Экран входа должен выглядеть так:
Android | iOS |
|
|
5. Как изменить типографику и стили ярлыков
Помимо изменений цвета, дизайнер также предоставил нам определенные шрифты. В ThemeData Flutter входят три темы текста. Каждая тема текста представляет собой набор стилей, например "Заголовок" и "Название". Мы используем несколько стилей для нашего приложения и изменим некоторые значения.
Как настроить тему текста
Чтобы импортировать шрифты в проект, их нужно добавить в файл pubspec.yaml.
В файле pubspec.yaml добавьте следующий код сразу после тега flutter::
# TODO: Insert Fonts (103)
fonts:
- family: Rubik
fonts:
- asset: fonts/Rubik-Regular.ttf
- asset: fonts/Rubik-Medium.ttf
weight: 500
Теперь вы можете использовать шрифт Rubik.
Устранение неполадок с файлом pubspec
Если вы скопируете и вставите приведенную выше декларацию, при запуске pub get могут возникнуть ошибки. Если вы получаете ошибки, сначала удалите пробелы в начале строки и замените их пробелами, используя отступ в два пробела. (Два пробела перед
fonts:
, четыре пробела перед
family: Rubik
и т. д.).
Если вы видите сообщение Сопоставление значений здесь не допускается, проверьте отступы в строке с проблемой и в строках выше.
В login.dart измените следующие строки в Column():
Column(
children: <Widget>[
Image.asset('assets/diamond.png'),
const SizedBox(height: 16.0),
Text(
'SHRINE',
style: Theme.of(context).textTheme.headlineSmall,
),
],
)
В app.dart добавьте после _buildShrineTheme() следующую строку:
// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
return base
.copyWith(
headlineSmall: base.headlineSmall!.copyWith(
fontWeight: FontWeight.w500,
),
titleLarge: base.titleLarge!.copyWith(
fontSize: 18.0,
),
bodySmall: base.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 14.0,
),
bodyLarge: base.bodyLarge!.copyWith(
fontWeight: FontWeight.w500,
fontSize: 16.0,
),
)
.apply(
fontFamily: 'Rubik',
displayColor: kShrineBrown900,
bodyColor: kShrineBrown900,
);
}
Этот параметр принимает значение TextTheme и меняет внешний вид заголовков, названий и подписей.
Применение fontFamily таким образом применяет изменения только к значениям масштаба типографики, указанным в copyWith() (заголовок, название, подпись).
Для некоторых шрифтов мы задаем пользовательское значение fontWeight с шагом 100: w500 (насыщенность 500) соответствует средней насыщенности, а w400 – обычной.
Как использовать новые темыtехt
Добавьте следующие темы в _buildShrineTheme после ошибки:
// TODO: Add the text themes (103)
textTheme: _buildShrineTextTheme(base.textTheme),
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePink100,
),
Сохранить проект. На этот раз также перезапустите приложение (горячий перезапуск), поскольку мы изменили шрифты.
Android | iOS |
|
|
Текст на экране входа и главном экране выглядит по-разному: некоторые элементы написаны шрифтом Rubik, а другие отображаются коричневым цветом вместо черного или белого. Значки также отображаются коричневым цветом.
Как уменьшить текст
Ярлыки слишком большие.
В файле home.dart измените children: самого внутреннего столбца:
// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)
Text(
product.name,
style: theme.textTheme.button,
softWrap: false,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
const SizedBox(height: 4.0),
Text(
formatter.format(product.price),
style: theme.textTheme.bodySmall,
),
// End new code
],
Как центрировать и переносить текст
We want to center the labels, and align the text to the bottom of each card, instead of the bottom of each image.
Переместите ярлыки в конец (низ) главной оси и измените их положение на центрированное:
// TODO: Align labels to the bottom and center (103)
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
Сохранить проект.
Android | iOS |
|
|
Так гораздо лучше.
Как задать тему для текстовых полей
Вы также можете настроить оформление текстовых полей с помощью InputDecorationTheme.
В файле app.dart в методе _buildShrineTheme() укажите значение inputDecorationTheme::
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
Сейчас текстовые поля имеют оформление filled. Давайте удалим его. Если удалить filled и указать inputDecorationTheme, текстовые поля будут иметь стиль контура.
В поле login.dart удалите значения filled: true:
// Remove filled: true values (103)
TextField(
controller: _usernameController,
decoration: const InputDecoration(
// Removed filled: true
labelText: 'Username',
),
),
const SizedBox(height: 12.0),
TextField(
controller: _passwordController,
decoration: const InputDecoration(
// Removed filled: true
labelText: 'Password',
),
obscureText: true,
),
Горячий перезапуск. Когда вы вводите имя пользователя, экран входа должен выглядеть так:
Android | iOS |
|
|
При вводе текста в текстовое поле границы и плавающие ярлыки отображаются основным цветом. но мы не можем легко его увидеть. Он недоступен для людей, которым сложно различать пиксели с недостаточным цветовым контрастом. Дополнительную информацию можно найти в руководстве по внедрению Material Design.
В app.dart укажите focusedBorder: в разделе inputDecorationTheme: :
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
),
Затем укажите floatingLabelStyle: в разделе inputDecorationTheme: :
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
Наконец, давайте сделаем так, чтобы кнопка "Отмена" использовала не основной, а дополнительный цвет, чтобы повысить контрастность.
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
primary: Theme.of(context).colorScheme.secondary,
),
),
Сохранить проект.
Android | iOS |
|
|
6. Как изменить высоту
Теперь, когда вы оформили страницу с определенным цветом и типографикой, соответствующими Shrine, давайте отрегулируем высоту.
Как изменить высоту кнопки "Далее"
По умолчанию для объекта типа ElevatedButton задано значение 2. Давайте поднимем его выше.
В login.dart добавьте значение style: в ElevatedButton NEXT:
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
),
),
Сохранить проект.
Android | iOS |
|
|
Как настроить высоту карточки
Сейчас карточки расположены на белом фоне рядом с навигацией по сайту.
В home.dart добавьте значение elevation: в Cards:
// TODO: Adjust card heights (103)
elevation: 0.0,
Сохраните проект.
Android | iOS |
|
|
Вы убрали тень под карточками.
7. Добавить фигуру
Shrine имеет классный геометрический стиль, определяющий элементы восьмиугольной или прямоугольной формы. Давайте добавим этот стиль в карточки на главном экране, а также в текстовые поля и кнопки на экране входа.
Изменить форму текстовых полей на экране входа
В app.dart импортируйте следующий файл:
import 'supplemental/cut_corners_border.dart';
В app.dart измените тему оформления текстового поля, чтобы использовать границу со скошенными углами:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
Как изменить форму кнопок на экране входа
В login.dart добавьте скошенную прямоугольную рамку к кнопке Отменить:
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
foregroundColor: kShrineBrown900,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
),
У TextButton нет видимой формы, поэтому зачем добавлять форму границы? Поэтому анимация пульсации привязана к той же форме при касании.
Теперь добавьте такую же фигуру к кнопке NEXT (Далее):
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
shape: const BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(7.0)),
),
),
),
Чтобы изменить форму всех кнопок, можно также использовать elevatedButtonTheme или textButtonTheme в app.dart. Это мы оставляем на усмотрение учащегося.
Горячий перезапуск.
Android | iOS |
|
|
8. Как изменить макет
Теперь изменим макет, чтобы карточки имели разное соотношение сторон и размер и каждая из них выглядела уникально.
Замена GridView на AsymmetricView
Мы уже написали файлы для асимметричного макета.
В home.dart добавьте следующий импорт:
import 'supplemental/asymmetric_view.dart';
Удалите _buildGridCards и замените body:
body: AsymmetricView(
products: ProductsRepository.loadProducts(Category.all),
),
Сохраните проект.
Android | iOS |
|
|
Теперь товары прокручиваются по горизонтали в виде узора.
9. Попробовать другую тему (необязательно)
Цвет – это мощный инструмент для продвижения бренда, и даже небольшое изменение цвета может сильно повлиять на пользовательский опыт. Чтобы проверить это, давайте посмотрим, как будет выглядеть Shrine, если цветовая схема бренда будет немного другой.
Как изменить цвета
В colors.dart добавьте следующий цвет:
const kShrinePurple = Color(0xFF5D1049);
В app.dart измените функцию _buildShrineTheme() на следующую:
ThemeData _buildShrineTheme() {
final ThemeData base = ThemeData.light();
return base.copyWith(
colorScheme: base.colorScheme.copyWith(
primary: kShrinePurple,
secondary: kShrinePurple,
error: kShrineErrorRed,
),
scaffoldBackgroundColor: kShrineSurfaceWhite,
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePurple,
),
appBarTheme: const AppBarTheme(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
),
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrinePurple,
),
),
floatingLabelStyle: TextStyle(
color: kShrinePurple,
),
),
);
}
Горячий перезапуск. Новая тема должна появиться.
Android | iOS |
|
|
Android | iOS |
|
|
Результат очень отличается! Давайте вернем app.dart's _buildShrineTheme к тому, что было до этого шага. Или скачайте шаблонный код для урока 104.
10. Поздравляем!
К этому моменту вы создали приложение, которое соответствует спецификациям дизайна от вашего дизайнера.
Дальнейшие действия
Вы использовали следующие компоненты Material Flutter: тему, типографику, высоту и форму. Другие компоненты и подсистемы можно найти в библиотеке Material Flutter.
Изучите файлы в каталоге supplemental, чтобы узнать, как мы создали асимметричную сетку с горизонтальной прокруткой.
Что делать, если запланированный дизайн приложения содержит элементы, для которых нет компонентов в библиотеке? В MDC-104: дополнительные компоненты Material Design мы рассказываем, как создавать собственные компоненты с помощью библиотеки Material Flutter.


























