Help us understand the problem. What is going on with this article?

FlutterのThemeを可能な限り柔軟性を持たせてみた

More than 1 year has passed since last update.

はじめに

Flutterのテーマはマテリアルデザインに100%準拠している場合はとても便利だと思うんですが、例えばbuttonThemeが一つしか設定できなくて柔軟性に欠けているように思えます。画面によってもっといろんなデザインに変えたい!(Buttonの形を変えたい、フォントスタイルもっと柔軟に変えたい)
ということで今回は、Themeをもっと柔軟に使えるようにしてみました。

最適化

ファイル構成

└─lib
  └─theme
    ├─theme.dart
    ├─text_theme_custom.dart
    ├─color_theme_custom.dart
    └─style_theme_custom.dart

ファイル構成はこんな感じでText、Color、Styleそれぞれ別ファイルで定義するようにしました。

theme.dart

theme.dartではThemeDataを返却するメソッドを定義します。

theme.dart
ThemeData createTheme() {

  return ThemeData(
      primarySwatch: ColorThemeCustom.customSwatch,
      primaryColor: ColorThemeCustom.customPrimaryColor,
      brightness: Brightness.light,
      primaryColorBrightness: Brightness.light,
      buttonTheme: StyleThemeCustom.createButtonTheme().copyWith(shape: StyleThemeCustom.round),
      textTheme: textTheme,
      primaryTextTheme: textTheme,
      accentTextTheme: textTheme,
    );
}

text_theme_custom.dart

デフォルト値をcreateTextThemeとして定義。フォントサイズ、フォントカラーは柔軟に変更できるように別途定義します。

text_theme_custom.dart
class TextThemeCustom {
  TextThemeCustom._();

  static TextTheme createTextTheme() {
    return TextTheme(
      headline: TextStyle(
        color: ColorThemeCustom.theme["black"],
        fontWeight: FontWeight.w400,
        fontStyle: FontStyle.normal,
      ).merge(font_size_18),
      body2: TextStyle(
          color: ColorThemeCustom.theme["black"],
          height: 1.0
      ).merge(font_normal).merge(font_size_15),
      body1: TextStyle(
        color: Color(0x8A1A1512),
      ).merge(font_normal).merge(font_size_15),
      button: TextStyle(
        color: ColorThemeCustom.theme["white"],
      ).merge(font_medium).merge(font_size_17),
      title: TextStyle(
        color: ColorThemeCustom.theme["black"],
      ).merge(font_medium).merge(font_size_17),
      subtitle: TextStyle(
        color: ColorThemeCustom.theme["black"],
      ).merge(font_medium).merge(font_size_16),
    );
  }
  static const TextStyle font_normal = const TextStyle(
    fontSize: 16.0,
    fontFamily: 'NotoSansCJKjp',
    fontWeight: FontWeight.normal,
    fontStyle: FontStyle.normal,
  );
  static const TextStyle font_medium = const TextStyle(
    fontSize: 16.0,
    fontFamily: 'NotoSansCJKjp',
    fontWeight: FontWeight.w500,
    fontStyle: FontStyle.normal,
  );
  static const TextStyle font_bold = const TextStyle(
    fontSize: 16.0,
    fontFamily: 'NotoSansCJKjp',
    fontWeight: FontWeight.bold,
    fontStyle: FontStyle.normal,
  );
  static const TextStyle font_size_15 = const TextStyle(fontSize: 15.0);
  static const TextStyle font_size_16 = const TextStyle(fontSize: 16.0);
  static const TextStyle font_size_17 = const TextStyle(fontSize: 17.0);
  static const TextStyle font_size_18 = const TextStyle(fontSize: 18.0);
  static const TextStyle font_size_22 = const TextStyle(fontSize: 22.0);
  static const TextStyle font_size_40 = const TextStyle(fontSize: 40.0);

  static const TextStyle font_color_primary = const TextStyle(color: ColorThemeCustom.customPrimaryColor);
}

color_theme_custom.dart

Primaryカラーや、Swatch、その他いろんな用途用にMapでカラーを定義します。

color_theme_custom.dart
class ColorThemeCustom {
  ColorThemeCustom._();

  static const int customPrimaryValue = 0xFFF5A076;
  static const Color customPrimaryColor = const Color(customPrimaryValue);
  static const MaterialColor customSwatch = const MaterialColor(
      customPrimaryValue,
      const <int, Color> {
        50: const Color(0xFFFFDDC1),
        100: const Color(0xFFFFD3B7),
        200: const Color(0xFFFFC9AE),
        300: const Color(0xFFFFBFA4),
        400: const Color(0xFFFFB59B),
        500: const Color(0xFFFFAB91),
        600: const Color(0xFFF29F86),
        700: const Color(0xFFE4937A),
        800: const Color(0xFFD7876F),
        900: const Color(0xFFC97B63),
      }
  );
  static const Map<String, Color> theme = const <String, Color>{
      "white": const Color(0xFFFFFFFF),
      "black": const Color(0xdd000000),
  };
}

style_theme_custom.dart

ButtonのデフォルトテーマをcreateButtonThemeとして定義、それ以外にround型ボタンやsquare型のボタンを使いたかったので別途StadiumBorder、RoundedRectangleBorder型の定数を定義。

style_theme_custom.dart
class StyleThemeCustom {
  StyleThemeCustom._();

  static ButtonThemeData createButtonTheme() {
    return ButtonThemeData(
      minWidth: 88.0,
      height: 36.0,
      padding: EdgeInsets.only(top: 0.0, bottom: 0.0, left: 16.0, right: 16.0),
      alignedDropdown: false,
      disabledColor: ColorThemeCustom.theme["black"],
      highlightColor: ColorThemeCustom.theme["black"],
    );
  }

  static const StadiumBorder round = StadiumBorder(
    side: BorderSide(
      color: ColorThemeCustom.theme["black"],
      width: 0.0,
      style: BorderStyle.none,
    ),
  );

  static const RoundedRectangleBorder square = RoundedRectangleBorder(
    side: BorderSide(
      color: ColorThemeCustom.theme["black"],
      width: 0.0,
      style: BorderStyle.none,
    ),
    borderRadius: BorderRadius.all(Radius.circular(10.0)),
  );
}

使い方

まずは今回作成したThemeDataをmain.dartで適用してあげます。

main.dart
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',
      theme: createTheme(),
      home: RandomWords(),
    );
  }
}

margeを使うことでthemeのマージ元をマージ先で上書きできます。

// テキスト
Text(
    "テキスト",
    style: Theme.of(context).textTheme.body1
        .merge(TextThemeCustom.font_size_22)
        .merge(TextThemeCustom.font_color_primary),
);
// or
Text(
    "テキスト",
    style: TextThemeCustom.font_normal
        .merge(TextThemeCustom.font_size_22)
        .merge(TextThemeCustom.font_color_primary),
);

// ボタン
RaisedButton(
    shape: StyleThemeCustom.square,
    onPressed: _pushSaved
);

終わりに

いかがでしたか?もっと便利な方法あったらぜひ教えて下さい!

参考

https://qiita.com/granoeste/items/352d19157c21cd35e21f

tarumzu
Android/Ruby/Docker/AWS/Vim
https://tarumzu.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away