Последнее обновление:
встраиваем темную тему в приложение

Быстрый способ встроить темную тему в приложение

Flutter

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

Причины просты: темная тема легче для глаз при использовании приложения ночью, это экономит заряд батареи, особенно если устройство использует OLED-экран, и самый важный из них : выглядит круто.

Обычно ответ разработчика на этот вопрос представляет собой некую вариацию следующего ответа:

Не сейчас. Было бы неплохо, но… может быть, позже

Понятно, что разработчики хотят минимизировать затраты на производство своего приложения, сосредоточившись на том, что действительно важно с точки зрения функциональности и стабильности. Но, неужели нужно чем-то жертвовать, чтобы получить темный режим? Давайте выясним.

Как и с чего начать?

Если вы хотите без особых усилий интегрировать темный режим в свое новое приложение, это не составит большого труда. Также можно добавить его в уже существующее приложение Flutter, но это потребует немного больше времени и некоторого рефакторинга.

Вот что нам понадобится:

  1. Адаптивные цвета
  2. Адаптивный стиль текста
  3. Способ переключения между темами

Адаптивные цвета

Лучше меньше, да лучше. Под этим я подразумеваю: постарайтесь свести количество цветов в вашем приложении к минимуму . Поверьте, вам не нужны все 50 оттенков серого.

Начнем с определения абстрактного класса для каждого цвета нашей темы:

abstract class LightThemeColors {
 static Color get background => const Color(0xFFFFFFFF);
 static Color get primaryContent => const Color(0xFF000000);
 static Color get primaryAccent => const Color(0xFF99283F);
}
 
abstract class DarkThemeColors {
 static Color get background => const Color(0xFF000000);
 static Color get primaryContent => const Color(0xFFE1E1E1);
 static Color get primaryAccent => const Color(0xFFC7482A);
}

Что касается цветов, которые следует использовать, обратите внимание на рекомендуемую цветовую палитру от Apple или рекомендации Google по материальному дизайну.

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

class ThemedColor {
 final Color light;
 final Color dark;
 
 const ThemedColor({
   @required this.light,
   @required this.dark,
 })  : assert(light != null),
       assert(dark != null);
 
 Color getColor(BuildContext context) {
   switch (Theme.of(context).brightness) {
     case Brightness.light:
       return light;
     case Brightness.dark:
       return dark;
   }
   throw UnsupportedError('${Theme.of(context).brightness} is not supported');
 }
}

На следующем этапе мы реализуем наш цветовой класс, который будем использовать во всем приложении:

abstract class AppColors {
 static Color background(BuildContext context) => ThemedColor(
       light: LightThemeColors.background,
       dark: DarkThemeColors.background,
     ).getColor(context);
 
 static Color primaryContent(BuildContext context) => ThemedColor(
       light: LightThemeColors.primaryContent,
       dark: DarkThemeColors.primaryContent,
     ).getColor(context);
 
 static Color primaryAccent(BuildContext context) => ThemedColor(
       light: LightThemeColors.primaryAccent,
       dark: DarkThemeColors.primaryAccent,
     ).getColor(context);
}

Теперь можно использовать этот класс везде, где у нас есть доступ к текущему BuildContext следующим образом:

Widget _buildButton(BuildContext context) {
   return MaterialButton(
     onPressed: onPressed,
     color: AppColors.primaryAccent(context),
     child: _buildButtonContent(),
   );
 }

Адаптивные стили текста

С цветами разобрались, теперь сосредоточимся на создании различных стилей текста.

abstract class AppTextStyles {
static const fontFamily = 'ВСТАВЬТЕ НАЗВАНИЕ ВАШЕГО ШРИФТА';
 
// СТИЛЬ ЗАГОЛОВКОВ //

 static TextStyle headline1(BuildContext context, {Color color}) {
   return TextStyle(
     color: color ?? AppColors.primaryContent(context),
     fontSize: 34,
     fontFamily: fontFamily,
     fontWeight: FontWeight.bold,
   );
 }
 
//   СТИЛЬ ТЕКСТА 1   //

 static TextStyle body1(BuildContext context, {Color color}) {
   return TextStyle(
     color: color ?? AppColors.primaryContent(context),
     fontSize: 18,
     fontFamily: fontFamily,
     fontWeight: FontWeight.bold,
   );
 }
 
//   СТИЛЬ ТЕКСТА 2   //

 static TextStyle subtitle1(BuildContext context, {Color color}) {
   return TextStyle(
     color: color ?? AppColors.primaryContent(context),
     fontSize: 16,
     fontFamily: fontFamily,
     fontWeight: FontWeight.normal,
   );
 }
}

Как и в случае с цветовым классом, мы можем использовать эти стили везде, где есть BuildContext. Например так:

Widget _buildTitleText(BuildContext context) {
   return Text(
     title,
     style: AppTextStyles.body1(
       context,
       color: AppColors.primaryAccent(context),
     ),
   );
 }

Начинаем волшебство

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

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

final Map<ThemeMode, ThemeData> appThemes = {
 ThemeMode.light: ThemeData(
   accentColor: LightThemeColors.primaryAccent,
   scaffoldBackgroundColor: LightThemeColors.background,
   brightness: Brightness.light,
 ),
 ThemeMode.dark: ThemeData(
   accentColor: DarkThemeColors.primaryAccent,
   scaffoldBackgroundColor: DarkThemeColors.background,
   brightness: Brightness.dark,
 )
};

Последний момент - нужно указать нашему MaterialApp переключаться между заданными темами следующим образом:

Widget _buildMaterialApp() {
   return MaterialApp(
     title: MyApp.appName,
   themeMode: ThemeMode.system,
     theme: appThemes[ThemeMode.light],
     darkTheme: appThemes[ThemeMode.dark],
     routes: navigationRoutes,
     home: _buildHome(),
   );
 }

Также можно вручную указать свойство themeMode в MaterialApp, которое позволит нам предоставить пользователю полный контроль над отображаемой темой. Пользователь сам решит, какую тему он хочет использовать, выбрав соответствующий вариант в настройках приложения.

На этом все! И, как вы только что убедились, ничего сложного во внедрении темной темы нет.

Комментарии