Если говорить о самых проблематичных аспектах обновления до Flutter 3.16, то это точно Material 3 по умолчанию (M3).
Не потому что в M3 много багов или использование его стало сложнее с версией 3.16, но поскольку хотя с версии 3.16 значение параметра useMaterial3
в MaterialApp
по умолчанию установлено как true, вы всё равно можете использовать useMaterial3: false
, чтобы отключить этот режим.
Почему же это считается проблемой? Потому что в будущем компоненты Material 2 будут отключены и удалены, поэтому переход на M3 — это предупреждение, которое можно игнорировать, используя useMaterial3: false
. Однако эта техническая задолженность может стать серьёзной проблемой в будущем.
Будете ли вы продолжать работать без обновлений?
Почему это так важно? Потому что адаптация к M3 требует значительных усилий, особенно если учесть все детали. M3 представляет собой новую цветовую схему, которая полностью отличается от схемы M2:
Как показано на изображении выше, видим следующие изменения:- Изменение цветовой схемы AppBar
FloatingActionButton
из круглого в прямоугольное с изменением цветаElevatedButton
и TextButton
FloatingActionButton
? Будете ли вы корректировать каждый AppBar
вручную? Есть ли возможность глобальной конфигурации для ElevatedButton
и TextButton
? В этой статье мы предоставляем рекомендации по адаптации, чтобы помочь вам преодолеть эти трудности.Основная причина проблемы заключается в том, что мало кто из китайских продуктов использует Material Design. Переход от M2 к M3 для разработчиков является чистым негативным изменением.
Сначала отметим, что официальная рекомендация по использованию цветовых схем для Material 3 — это метод ColorScheme.fromSeed()
, который позволяет создать цветовую схему. Конечно, вы также можете использовать ColorScheme.fromImageProvider
для создания цветовой схемы на основе изображения, однако большинство людей скорее всего этого не сделает. Также есть метод ColorScheme.fromSwatch
, но он менее гибкий по сравнению с fromSeed
, поэтому последний вариант является лучшим выбором.
Поскольку по умолчанию цветовая схема M3 переходит с синего на фиолетовый, если вы используете стандартную цветовую схему, вам потребуется её настроить. Цель данной статьи — восстановление внешнего вида приложения M2 при работе с M3, поскольку это действительно больше, чем просто изменение цвета.
Если ваш прежний
ThemeData
выглядел как приведённый ниже код, то после выполнения вы заметите, что вместо обычного списка с эффектом M2, который должен был быть, теперь есть некий "неописуемый" эффект M3. Видно, что в данном случаеprimarySwatch
не играет никакой роли.
ThemeData(
primarySwatch: Colors.blue,
////
)
M2 | M3 |
---|---|
![]() |
![]() |
Сначала нам нужно добавить colorScheme
. Однако, после добавления этого свойства ничего не изменится, так как компонент всё ещё находится под влиянием цветовой схемы M3. Поэтому следующим шагом будет глобальное восстановление AppBar
.
ThemeData(
primarySwatch: Colors.blue,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
Делай это.
Как показано ниже, мы сначала добавляем AppBarTheme
, чтобы фон AppBar
снова стал синим. Но при этом текст и значки AppBar
остаются чёрными.
ThemeData(
primarySwatch: Colors.blue,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
appBarTheme: AppBarTheme(
backgroundColor: Colors.blue,
),
),
| |
|
| ------------------------------------------------------ | ------------------------------------------------------ |Чтобы вернуть значки и текст к белому цвету, характерному для M2, можно настроить
iconTheme
и titleTextStyle
внутри AppBarTheme
. После настройки видно, что UI компонента AppBar
полностью восстановлен до состояния M2. Возможно, вас интересует вопрос, почему конфигурация включает значения size: 24.0
и Typography.dense2021.titleLarge
?```dart
AppBarTheme(
iconTheme: IconThemeData(
color: Colors.white,
size: 24.0,
),
backgroundColor: Colors.blue,
titleTextStyle: Typography.dense2014.titleLarge,
)
 Это суть всей статьи: **восстановление M3 UI до состояния M2 при отсутствии удаления контрола M2**.
Например, в исходном коде версии 3.16 часто встречается конструкция `theme.useMaterial3 ?`, а внутри компонента `AppBar`:
- В `_AppBarDefaultsM3` цвет иконки задается через поле `onSurface`, размер — 24 пикселя;
- В `_AppBarDefaultsM2` иконка использует дефолтные настройки темы, то есть размер — 24 пикселя, цвет — белый.

| M2 | M3 |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|  |  |
Поэтому мы можем использовать конфигурацию `IconThemeData` со значениями `color: Colors.white, size: 24.0`, чтобы восстановить состояние M2.
> Конечно, вы можете также изменять цвет через поле `onSurface` в `ColorScheme`, но это затронет слишком много мест, поэтому рекомендую использовать конфигурацию `IconThemeData` в `AppBarTheme`.Кроме того, можно заметить наличие ещё одного поля `Typography.dense2014.titleLarge`. Откуда взялось это поле? Вернёмся к `_AppBarDefaultsM3`: в M3 AppBar используется поле `textTheme.titleLarge` из `ThemeData`, а дефолтные шрифтные настройки берутся из объекта `Typography`.

Объект `Typography` содержит множество дефолтных настроек шрифтов, например, `Typography.dense2014` имеет следующие настройки. Из вышеупомянутого кода видно, что **по умолчанию M2 использует `Typography.material2014`, которое совпадает с `Typography.dense2014`**, то есть использование `Typography.dense2014.titleLarge` в AppBar позволяет восстановить текстовый стиль AppBar M3 до состояния M2.

Дошли ли вы до этого места и поняли основной подход?
**С помощью условия `theme.useMaterial3` находите контролы, затем в исходном коде находитесь реализация M2, после чего модифицируете её в глобальном темовом конфигурационном файле**, например, для AppBar используется конфигурация `AppBarTheme`. Если реализация M2 использует какие-либо дефолтные настройки, следует найти их происхождение. Таким образом, работа с M3 требует значительных усилий.
## Карточка (Card)
Как показано на рисунке ниже, это изменения компонента `Card` между версиями M2 и M3. Вместо стандартной закруглённой формы цвет карточки изменился с белого на светло-голубой. Однако здесь есть небольшое ограничение: даже если вы установите цвет карточки как `Colors.white`, она всё равно будет иметь этот голубой оттенок.| M2 | M3 |
| ------------------------------------------------------- | ------------------------------------------------------- |
|  |  |
Как можно удалить этот цвет? Достаточно просто установить значение `surfaceTint` в `ColorScheme` на прозрачность. Как показано на следующих рисунках, эффект карточки реализован через использование компонента `Material`. В версии M3 `Material` использует значения `elevation` и `surfaceTint` для создания поверхности.
```dart
ColorScheme.fromSeed(
seedColor: Colors.blue,
/// влияет на цвет поверхности карточки, так как в M3 используется applySurfaceTint в Material
surfaceTint: Colors.transparent,
),
Поэтому, чтобы удалить этот голубой оттенок, достаточно установить surfaceTint
на прозрачность. Аналогичная логика применима и к компоненту BottomAppBar
. Таким образом, если вам требуется восстановить внешний вид этих компонентов до состояния M2, достаточно установить surfaceTint
на прозрачность.
Аналогичные изменения являются самыми сложными моментами при переходе на M3. Если вы не знакомы с внутренней реализацией этих компонентов, то после обновления вы можете столкнуться с тем, что, несмотря на указание белого цвета, карточка имеет светло-голубой оттенок. Это может стать настоящим испытанием для разработчиков. Поэтому здесь мы предлагаем использовать карточку (
Card
) как пример решения этой проблемы.Ещё один типичный компонент — это FloatingActionButton
(FAB).
Основное изменение компонента FloatingActionButton
(FAB) между версиями M2 и M3 заключается в том, что он стал прямоугольным вместо круглого. Кроме того, его цвет больше не зависит от основного цвета темы. Мы можем не говорить сейчас о том, является ли эта "оптимизация" положительной или отрицательной, но рассмотрим, как можно вернуть FAB к внешнему виду версии M2.| M2 | M3 |
| ------------------------------------------------------- | ------------------------------------------------------- |
| |
|
Сначала следует конфигурация параметра с именем floatingActionButtonTheme
, который можно использовать для настройки FloatingActionButtonThemeData
. Поэтому мы добавляем эту конфигурацию, возвращаем форму кнопки обратно к круглой форме и меняем цвет фона (backgroundColor
) на синий.
floatingActionButtonTheme: FloatingActionButtonThemeData(
backgroundColor: Colors.blue,
shape: CircleBorder()
),
Осталось настроить цвет иконки. Мы можем изменить цвет иконки на белый каждый раз, когда используем Icon
, но нам требуется глобальная конфигурация по умолчанию, чтобы вернуться к состоянию до M2. Для этого нам нужно найти, как цвет иконки получается внутри FAB.
Поиск реализации этого цвета привел меня в долгое путешествие...Изначально
Icon
получает свой цвет по умолчанию черезIconThemeData
. Так как в теме FAB нет возможности настроитьiconTheme
, то логично было бы установить глобальное значениеiconTheme: IconThemeData
. Однако после настройки это не работало.
Дальнейший поиск показал, что FAB использует RawMaterialButton
для отображения иконки при нажатии. Внутри RawMaterialButton
используется метод IconTheme.merge
, поэтому по умолчанию цвет иконки внутри FAB определяется значением effectiveTextColor
.
После длительного поиска связей между компонентами стало понятно:
effectiveTextColor
берётся из TextSytle
переданного в FAB.textStyle
берётся из extendedTextStyle
.extendedTextStyle
берётся из foregroundColor
.foregroundColor
по умолчанию берётся из floatingActionButtonTheme.foregroundColor
.Похоже, что проблема была решена, необходимо глобально установить цвет иконки внутри FAB, для этого следует настроить foregroundColor
в FloatingActionButtonThemeData
. Как можно было бы догадаться, такое решение и название могут быть непонятны большинству.
К тому же, передача таких настроек является довольно "скрытой", что делает FAB отличным примером сложностей управления темами в Flutter: глубокие уровни передачи, сложные ссылки на темы, а также скрытые реализации слияния/copy.```dart floatingActionButtonTheme: FloatingActionButtonThemeData( backgroundColor: Colors.blue, foregroundColor: Colors.blue, shape: CircleBorder() ),
Кроме того, есть ещё одна интересная особенность **`IconThemeData`: при отсутствии полной конфигурации, то есть когда `isConcrete` не удовлетворено, остальные параметры будут заменены значениями по умолчанию при вызове `of(context)`**. Это важно для понимания процесса адаптации между Material Design 3 и Material Design 2.



# primarySwatch
И последнее, поговорим о `primarySwatch` в `ThemeData`. Почему мы говорим об этом? Потому что если вы используете `primaryColorDark` и `primaryColorLight` как настройки, после использования `ColorScheme.fromSeed`, они могут измениться таким образом, что восстановление до состояния Material Design 2 потребует установки `primarySwatch`.



# Заключение
Ниже приведён пример кода, который используется для перехода с Material Design 3 на Material Design 2. Хотя переход на Material Design 3 может представлять собой положительное обновление для команды Flutter, для пользователей в Китае это может быть отрицательным шагом, так как многие предпочитают более простую и знакомую версию дизайна.
```dart
return ThemeData(
/// Для корректной работы `Theme.of(context).primaryColorLight` и `primaryColorDark`
/// рекомендуется указывать `primarySwatch`.
primarySwatch: color as MaterialColor,
)
``` /// В режиме Material Design 3 компонент Card будет использовать overlay
colorScheme: ColorScheme.fromSeed( seedColor: цвет, primary: цвет,
brightness: Brightness.light,
/// влияет на оттенок карточки, так как в M3 используется applySurfaceTint, а в Material — нет
surfaceTint: Colors.transparent,
),
/// вдохновлено значением iconThemeData.isConcrete, требуется полный набор параметров, чтобы избежать использования значения по умолчанию iconTheme: IconThemeData( size: 24.0, fill: 0.0, weight: 400.0, grade: 0.0, opticalSize: 48.0, color: Colors.white, opacity: 0.8, ),
/// изменение поведения по умолчанию для FloatingActionButton floatingActionButtonTheme: FloatingActionButtonThemeData( foregroundColor: Colors.white, backgroundColor: цвет, shape: CircleBorder()), appBarTheme: AppBarTheme( iconTheme: IconThemeData( color: Colors.white, size: 24.0, ), backgroundColor: цвет, titleTextStyle: Typography.dense2014.titleLarge, systemOverlayStyle: SystemUiOverlayStyle.light, ),
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )