在Flutter開發中,我們可以通過定義
Theme
,複用顏色和字型樣式,從而讓整個app的設計看起來更一致。
一. Theme主題的使用
Theme分為:全域性Theme和區域性Theme
主題有兩個作用:
設定了主題之後,某些Widget會自動使用主題的樣式(比如AppBar的顏色) 將某些樣式放到主題中統一管理,在應用程式的其它地方直接引用
1.1. 全域性Theme
全域性Theme會影響整個app的顏色和字型樣式。
使用起來非常簡單,只需要向MaterialApp構造器傳入 ThemeData
即可。
如果沒有設定Theme,Flutter將會使用預設的樣式。 當然,我們可以對它進行定製。
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// 1.亮度: light-dark
brightness: Brightness.light,
// 2.primarySwatch: primaryColor/accentColor的結合體
primarySwatch: Colors.red,
// 3.主要顏色: 導航/底部TabBar
primaryColor: Colors.pink,
// 4.次要顏色: FloatingActionButton/按鈕顏色
accentColor: Colors.orange,
// 5.卡片主題
cardTheme: CardTheme(
color: Colors.greenAccent,
elevation: 10,
shape: Border.all(width: 3, color: Colors.red),
margin: EdgeInsets.all(10)
),
// 6.按鈕主題
buttonTheme: ButtonThemeData(
minWidth: 0,
height: 25
),
// 7.文字主題
textTheme: TextTheme(
title: TextStyle(fontSize: 30, color: Colors.blue),
display1: TextStyle(fontSize: 10),
)
),
home: HYHomePage(),
);
}
}
複製程式碼
1.2. 區域性Theme
如果某個具體的Widget不希望直接使用全域性的Theme,而希望自己來定義,應該如何做呢?
非常簡單,只需要在Widget的父節點包裹一下Theme即可
建立另外一個新的頁面,頁面中使用新的主題:
在新的頁面的Scaffold外,包裹了一個Theme,並且設定data為一個新的ThemeData
class HYSecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Theme(
data: ThemeData(),
child: Scaffold(
),
);
}
}
複製程式碼
但是,我們很多時候並不是想完全使用一個新的主題,而且在之前的主題基礎之上進行修改:
class HYSecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
primaryColor: Colors.greenAccent
),
child: Scaffold(
),
);
}
}
複製程式碼
1.3. Flutter中文網錯誤
但是這裡有一個注意事項:accentColor在這裡並不會被覆蓋。
為什麼不能覆蓋呢?https://github.com/material-components/material-components-flutter-codelabs/issues/106
我摘抄一點官方人員的回覆:
其實官網文件中之前也出現了類似的錯誤,比如Flutter中文網之前是翻譯官方文件的
https://flutterchina.club/cookbook/design/themes/其中就有該錯誤
後來官網文件中對這個問題進行了修正:
二. 暗黑Theme適配
2.1. darkTheme
目前很多應用程式都需要適配暗黑模式,Flutter中如何做到暗黑模式的適配呢?
事實上,MaterialApp中有theme和dartTheme兩個引數:
按照下面的寫法,我們已經預設適配了暗黑主題
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
home: HYHomePage(),
);
}
}
複製程式碼
2.2. 開發中適配
在開發中,為了能適配兩種主題(設定是更多的主題),我們可以封裝一個AppTheme
1.公共的樣式抽取成常量 2.封裝一個亮色主題 3.封裝一個暗黑主題
import 'package:flutter/material.dart';
class AppTheme {
// 1.抽取相同的樣式
static const double _titleFontSize = 20;
// 2.亮色主題
static final ThemeData lightTheme = ThemeData(
primarySwatch: Colors.pink,
primaryTextTheme: TextTheme(
title: TextStyle(
color: Colors.yellow,
fontSize: _titleFontSize
)
),
textTheme: TextTheme(
body1: TextStyle(color: Colors.red)
)
);
// 3.暗黑主題
static final ThemeData darkTheme = ThemeData(
primaryColor: Colors.grey,
primaryTextTheme: TextTheme(
title: TextStyle(
color: Colors.white,
fontSize: _titleFontSize
)
),
textTheme: TextTheme(
title: TextStyle(color: Colors.white),
body1: TextStyle(color: Colors.white70)
)
);
}
複製程式碼
在MaterialApp中,可以決定使用哪一個主題:
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
home: HYHomePage(),
);
}
}
複製程式碼
備註:所有內容首發於公眾號,之後除了Flutter也會更新其他技術文章,TypeScript、React、Node、uniapp、mpvue、資料結構與演算法等等,也會更新一些自己的學習心得等,歡迎大家關注