前言
一般情況下,我們的Application都有獨特的特點,UI設計師會結合業務和品牌的特點,指定元件的視覺定製。包含主題色,圓角,邊框等各種樣式定製。
我們就需要使用 Theme 在應用程式中定製全域性顏色和各種樣式。
當我們不設定主題時,系統會生成預設主題。比如我們最熟悉的primaryColor,預設顏色是Colors.blue,Brightness預設值Brightness.light.
官方關於主題的介紹請點選 使用主題共享顏色和字型樣式。
設定主題的兩種方式
方式一:全域性設定
全域性設定主題就是在應用程式根MaterialApp定製ThemeData.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Theme',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
複製程式碼
方式二:區域性設定
我們想要在某些特定的頁面,定製不一樣的主題,可以區域性設定Theme. 具體有兩種方式,分別是建立特有的ThemeData和擴充套件父主題。
建立特有的ThemeData(直接覆蓋父主題)
如果我們不想使用當初定製應用程式的主題,使用這種方式,可以直接覆蓋原有的父主題。
提示,Theme是一個Widget,繼承了StatelessWidget.
Theme(
data: ThemeData(
accentColor: Colors.yellow,
),
child: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
);
複製程式碼
擴充套件父主題
我們只需要改變ThemeData的某一項,可以使用 copyWith 擴充套件負主題。
Theme(
data: Theme.of(context).copyWith(accentColor: Colors.yellow),
child: FloatingActionButton(
onPressed: null,
child: Icon(Icons.add),
),
);
複製程式碼
獲取已設定的主題
通過Theme.of(context)函式獲取已設定的主題。
比如獲取primaryColor
Color primaryColor = Theme.of(context).primaryColor;
複製程式碼
ThemeData的主要屬性及預設值
提示:文字太長,如需查詢,使用 ctrl + f.
屬性 | 型別 | 描述 |
---|---|---|
brightness | Brightness | 有兩種可以選擇,Brightness.light和Brightness.dark |
primarySwatch | MaterialColor | MaterialColor間接繼承了Color |
primaryColor | Color | 主題色 |
primaryColorBrightness | Brightness | 判斷primaryColor是Brightness.light,還是Brightness.dark |
primaryColorLight | Color | primaryColor的較暗顏色 |
primaryColorDark | Color | primaryColor的較亮顏色 |
accentColor | Color | 文字、按鈕等前景色 |
accentColorBrightness | Brightness | accentColor的亮度,用於確定放置在突出顏色頂部的文字和圖示的顏色(例如FloatingButton上的圖示) |
canvasColor | Color | MaterialType.canvas Material的預設顏色 |
scaffoldBackgroundColor | Color | Material預設顏色 |
bottomAppBarColor | Color | BottomAppBar的預設顏色 |
cardColor | Color | Material被用作Card時的顏色 |
dividerColor | Color | Dividers和PopupMenuDividers的顏色,也用於ListTiles中間,和DataTables的每行中間 |
focusColor | Color | |
hoverColor | Color | |
highlightColor | Color | 用於類似墨水噴濺動畫或指示選單被選中的高亮顏色 |
splashColor | Color | 墨水噴濺的顏色 |
splashFactory | InteractiveInkFeatureFactory | 定義InkWall和InkResponse生成的墨水噴濺的外觀 |
selectedRowColor | Color | 選中行時的高亮顏色 |
unselectedWidgetColor | Color | 用於Widget處於非活動(但已啟用)狀態的顏色。 例如,未選中的核取方塊。 通常與accentColor形成對比 |
disabledColor | Color | 用於Widget無效的顏色,無論任何狀態。例如禁用核取方塊。 |
buttonColor | Color | Material中RaisedButtons使用的預設填充色。 |
buttonTheme | ButtonThemeData | 定義了按鈕等控制元件的預設配置,像RaisedButton和FlatButton |
toggleButtonsTheme | ToggleButtonsThemeData | 定義ToggleButtons控制元件的預設配置 |
secondaryHeaderColor | Color | 有選定行時PaginatedDataTable標題的顏色。 |
textSelectionColor | Color | 文字欄位中選中文字的顏色,例如TextField。 |
cursorColor | Color | 游標顏色 |
textSelectionHandleColor | Color | 用於調整當前文字的哪個部分的控制程式碼顏色。 |
backgroundColor | Color | 作為Scaffold基礎的Material預設顏色,典型Material應用或應用內頁面的背景顏色。 |
dialogBackgroundColor | Color | Dialog元素的背景色。 |
indicatorColor | Color | TabBar中選項選中的指示器顏色。 |
hintColor | Color | 用於提示文字或佔位符文字的顏色,例如在TextField中。 |
errorColor | Color | 用於輸入驗證錯誤的顏色,例如在TextField中。 |
toggleableActiveColor | Color | 用於突出顯示切換Widget(如Switch,Radio和Checkbox)的活動狀態的顏色。 |
fontFamily | String | 字型系列,如“Roboto” |
textTheme | TextTheme | 文字預設主題 |
primaryTextTheme | TextTheme | 一個與主色對比的文字主題 |
accentTextTheme | TextTheme | 與突出顏色對照的文字主題。 |
inputDecorationTheme | InputDecorationTheme | InputDecorator,TextField和TextFormField的預設InputDecoration值基於此主題。 |
iconTheme | IconThemeData | 與卡片和畫布顏色形成對比的圖示主題。 |
primaryIconTheme | IconThemeData | 一個與主色對比的圖片主題。 |
accentIconTheme | IconThemeData | 與突出顏色對照的圖片主題。 |
sliderTheme | SliderThemeData | 用於渲染Slider的顏色和形狀。 |
tabBarTheme | TabBarTheme | TabBar的預設出題 |
tooltipTheme | TooltipThemeData | 提示Tooltip的預設主題 |
cardTheme | CardTheme | Card的預設主題 |
chipTheme | ChipThemeData | 用於渲染Chip的顏色和樣式。 |
platform | TargetPlatform | Widget需要適配的目標型別。 |
materialTapTargetSize | MaterialTapTargetSize | |
applyElevationOverlayColor | bool | |
pageTransitionsTheme | PageTransitionsTheme | |
appBarTheme | AppBarTheme | AppBar預設主題 |
bottomAppBarTheme | BottomAppBarTheme | BottomAppBar的預設主題 |
colorScheme | ColorScheme | |
dialogTheme | DialogTheme | Dialog的預設主題 |
floatingActionButtonTheme | FloatingActionButtonThemeData | FloatingActionButton的預設主題 |
typography | Typography | |
cupertinoOverrideTheme | CupertinoThemeData | |
snackBarTheme | SnackBarThemeData | SnackBar的預設主題 |
bottomSheetTheme | BottomSheetThemeData | |
popupMenuTheme | PopupMenuThemeData | |
bannerTheme | MaterialBannerThemeData | |
dividerTheme | DividerThemeData |
ThemeData構造器原始碼
看原始碼更容易理解
brightness ??= Brightness.light;
final bool isDark = brightness == Brightness.dark;
primarySwatch ??= Colors.blue;
primaryColor ??= isDark ? Colors.grey[900] : primarySwatch;
primaryColorBrightness ??= estimateBrightnessForColor(primaryColor);
primaryColorLight ??= isDark ? Colors.grey[500] : primarySwatch[100];
primaryColorDark ??= isDark ? Colors.black : primarySwatch[700];
final bool primaryIsDark = primaryColorBrightness == Brightness.dark;
toggleableActiveColor ??= isDark ? Colors.tealAccent[200] : (accentColor ?? primarySwatch[600]);
accentColor ??= isDark ? Colors.tealAccent[200] : primarySwatch[500];
accentColorBrightness ??= estimateBrightnessForColor(accentColor);
final bool accentIsDark = accentColorBrightness == Brightness.dark;
canvasColor ??= isDark ? Colors.grey[850] : Colors.grey[50];
scaffoldBackgroundColor ??= canvasColor;
bottomAppBarColor ??= isDark ? Colors.grey[800] : Colors.white;
cardColor ??= isDark ? Colors.grey[800] : Colors.white;
dividerColor ??= isDark ? const Color(0x1FFFFFFF) : const Color(0x1F000000);
// Create a ColorScheme that is backwards compatible as possible
// with the existing default ThemeData color values.
colorScheme ??= ColorScheme.fromSwatch(
primarySwatch: primarySwatch,
primaryColorDark: primaryColorDark,
accentColor: accentColor,
cardColor: cardColor,
backgroundColor: backgroundColor,
errorColor: errorColor,
brightness: brightness,
);
splashFactory ??= InkSplash.splashFactory;
selectedRowColor ??= Colors.grey[100];
unselectedWidgetColor ??= isDark ? Colors.white70 : Colors.black54;
// Spec does not specify a dark theme secondaryHeaderColor, this is a guess.
secondaryHeaderColor ??= isDark ? Colors.grey[700] : primarySwatch[50];
textSelectionColor ??= isDark ? accentColor : primarySwatch[200];
// TODO(sandrasandeep): change to color provided by Material Design team
cursorColor = cursorColor ?? const Color.fromRGBO(66, 133, 244, 1.0);
textSelectionHandleColor ??= isDark ? Colors.tealAccent[400] : primarySwatch[300];
backgroundColor ??= isDark ? Colors.grey[700] : primarySwatch[200];
dialogBackgroundColor ??= isDark ? Colors.grey[800] : Colors.white;
indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor;
hintColor ??= isDark ? const Color(0x80FFFFFF) : const Color(0x8A000000);
errorColor ??= Colors.red[700];
inputDecorationTheme ??= const InputDecorationTheme();
pageTransitionsTheme ??= const PageTransitionsTheme();
primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
accentIconTheme ??= accentIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black87);
platform ??= defaultTargetPlatform;
typography ??= Typography(platform: platform);
final TextTheme defaultTextTheme = isDark ? typography.white : typography.black;
textTheme = defaultTextTheme.merge(textTheme);
final TextTheme defaultPrimaryTextTheme = primaryIsDark ? typography.white : typography.black;
primaryTextTheme = defaultPrimaryTextTheme.merge(primaryTextTheme);
final TextTheme defaultAccentTextTheme = accentIsDark ? typography.white : typography.black;
accentTextTheme = defaultAccentTextTheme.merge(accentTextTheme);
materialTapTargetSize ??= MaterialTapTargetSize.padded;
applyElevationOverlayColor ??= false;
if (fontFamily != null) {
textTheme = textTheme.apply(fontFamily: fontFamily);
primaryTextTheme = primaryTextTheme.apply(fontFamily: fontFamily);
accentTextTheme = accentTextTheme.apply(fontFamily: fontFamily);
}
// Used as the default color (fill color) for RaisedButtons. Computing the
// default for ButtonThemeData for the sake of backwards compatibility.
buttonColor ??= isDark ? primarySwatch[600] : Colors.grey[300];
focusColor ??= isDark ? Colors.white.withOpacity(0.12) : Colors.black.withOpacity(0.12);
hoverColor ??= isDark ? Colors.white.withOpacity(0.04) : Colors.black.withOpacity(0.04);
buttonTheme ??= ButtonThemeData(
colorScheme: colorScheme,
buttonColor: buttonColor,
disabledColor: disabledColor,
focusColor: focusColor,
hoverColor: hoverColor,
highlightColor: highlightColor,
splashColor: splashColor,
materialTapTargetSize: materialTapTargetSize,
);
toggleButtonsTheme ??= const ToggleButtonsThemeData();
disabledColor ??= isDark ? Colors.white38 : Colors.black38;
highlightColor ??= isDark ? _kDarkThemeHighlightColor : _kLightThemeHighlightColor;
splashColor ??= isDark ? _kDarkThemeSplashColor : _kLightThemeSplashColor;
sliderTheme ??= const SliderThemeData();
tabBarTheme ??= const TabBarTheme();
tooltipTheme ??= const TooltipThemeData();
appBarTheme ??= const AppBarTheme();
bottomAppBarTheme ??= const BottomAppBarTheme();
cardTheme ??= const CardTheme();
chipTheme ??= ChipThemeData.fromDefaults(
secondaryColor: primaryColor,
brightness: brightness,
labelStyle: textTheme.body2,
);
dialogTheme ??= const DialogTheme();
floatingActionButtonTheme ??= const FloatingActionButtonThemeData();
cupertinoOverrideTheme = cupertinoOverrideTheme?.noDefault();
snackBarTheme ??= const SnackBarThemeData();
bottomSheetTheme ??= const BottomSheetThemeData();
popupMenuTheme ??= const PopupMenuThemeData();
bannerTheme ??= const MaterialBannerThemeData();
dividerTheme ??= const DividerThemeData();
複製程式碼