LoginSignup
13
11

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-08-02

はじめに

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
);

終わりに

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

参考

13
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
11