MDC-103 Flutter: тематическое оформление Material Design с использованием цвета, формы, высоты и шрифта

1. Введение

logo_components_color_2x_web_96dp.png

Компоненты 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

Страница входа в Shrine, оформленная в коричневых и розовых тонах

Страница входа в Shrine, оформленная в коричневых и розовых тонах

Страница товара Shrine с верхней панелью приложения и асимметричной сеткой товаров с горизонтальной прокруткой, оформленная в розовых тонах

Компоненты и подсистемы 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

Как открыть проект и запустить приложение

  1. Откройте проект в любом редакторе.
  2. Следуйте инструкциям в разделе "Запустите приложение" статьи Начало работы: пробный запуск для выбранного редактора.

Готово! На устройстве должна появиться страница входа в Shrine из предыдущей лабораторной работы.

Android

iOS

страница входа в Shrine без темы;

Страница входа в Shrine без темы

Нажмите "Далее", чтобы перейти на страницу товара.

Android

iOS

страница Shrine с сеткой товаров без темы

страница с товарами Shrine без темы

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 из коричневого образца.

d0362cb45c565a8e.jpeg 470b0e1c2669ae2.png

Каждый цветной параметр виджета сопоставлен с цветом из этих схем. Например, цвет декораций текстового поля, когда оно активно принимает ввод, должен быть основным цветом темы. Если этот цвет плохо виден на фоне, используйте другой.

Теперь, когда мы выбрали цвета, которые хотим использовать, мы можем применить их к интерфейсу. Для этого мы зададим значения виджета 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

Страница входа в систему Shrine в розовых и коричневых тонах

Страница входа в систему Shrine в розовых и коричневых тонах

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

Страница входа в Shrine с фокусом на поле имени пользователя

Страница входа в Shrine с фокусом на поле имени пользователя

При вводе текста в текстовое поле границы и плавающие ярлыки отображаются основным цветом. но мы не можем легко его увидеть. Он недоступен для людей, которым сложно различать пиксели с недостаточным цветовым контрастом. Дополнительную информацию можно найти в руководстве по внедрению 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

Страница входа в Shrine с доступной кнопкой &quot;Отмена&quot;

Страница входа в Shrine с доступной кнопкой &quot;Отмена&quot;

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

Страница входа в Shrine с кнопкой &quot;Далее&quot;

Страница входа в Shrine с кнопкой &quot;Далее&quot;

Как настроить высоту карточки

Сейчас карточки расположены на белом фоне рядом с навигацией по сайту.

В 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

Страница входа в Shrine с примененной темой фигур

Страница входа в Shrine с примененной темой оформления

8. Как изменить макет

Теперь изменим макет, чтобы карточки имели разное соотношение сторон и размер и каждая из них выглядела уникально.

Замена GridView на AsymmetricView

Мы уже написали файлы для асимметричного макета.

В home.dart добавьте следующий импорт:

import 'supplemental/asymmetric_view.dart';

Удалите _buildGridCards и замените body:

body: AsymmetricView(
  products: ProductsRepository.loadProducts(Category.all),
),

Сохраните проект.

Android

iOS

Страница товара в формате Shrine с асимметричным макетом и горизонтальной прокруткой

Страница товара в формате Shrine с асимметричным макетом и горизонтальной прокруткой

Теперь товары прокручиваются по горизонтали в виде узора.

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

Страница входа в Shrine с фиолетово-розовой темой

Страница входа в Shrine с фиолетово-розовой темой

Android

iOS

Страница товара Shrine в розовых тонах

Страница товара Shrine в розовых тонах

Результат очень отличается! Давайте вернем app.dart's _buildShrineTheme к тому, что было до этого шага. Или скачайте шаблонный код для урока 104.

10. Поздравляем!

К этому моменту вы создали приложение, которое соответствует спецификациям дизайна от вашего дизайнера.

Дальнейшие действия

Вы использовали следующие компоненты Material Flutter: тему, типографику, высоту и форму. Другие компоненты и подсистемы можно найти в библиотеке Material Flutter.

Изучите файлы в каталоге supplemental, чтобы узнать, как мы создали асимметричную сетку с горизонтальной прокруткой.

Что делать, если запланированный дизайн приложения содержит элементы, для которых нет компонентов в библиотеке? В MDC-104: дополнительные компоненты Material Design мы рассказываем, как создавать собственные компоненты с помощью библиотеки Material Flutter.

Я смог выполнить эту практическую работу, потратив разумное количество времени и усилий

Однозначно да Да Нейтрально Нет Однозначно нет

Я хочу продолжать использовать компоненты Material в будущем

Однозначно да Да Затрудняюсь ответить Нет Однозначно нет