はじめに
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を返却するメソッドを定義します。
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として定義。フォントサイズ、フォントカラーは柔軟に変更できるように別途定義します。
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でカラーを定義します。
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型の定数を定義。
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で適用してあげます。
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
);
終わりに
いかがでしたか?もっと便利な方法あったらぜひ教えて下さい!
参考