Flutter 全局颜色和全局字体样式
一、前言
经常和UI打交道的前端开发者都明白,任何产品的视觉语言都需要统一。而这无外乎2个规范:字体规范 & 色彩规范。字体样式一般需要5~10种,色彩规范就很多了,但一般至少也需要5种以上,比如:
当我们在网上找flutter全局样式的时候,一般都会告诉你MaterialApp 已经事先为你预设了一个全局的 Theme Widget。我们可以配置 ThemeData
来定制全局颜色和全局字体样式,并在页面中使用Theme.of(context)
将定义好的颜色和字体样式取出。
但这个这个会直接修改Material设定好控件的默认样式,我们往下看。
二、全局颜色
1、我们可以在main.dart
里面定义全局的样式颜色,
// main.dart
MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primaryColor: Color(0xFF3533A4),
accentColor: Color(0xFF346DFC),
)
)
2、再到其他的页面中直接进行引用
Widget build(BuildContext context) {
final Color primaryColor = Theme.of(context).primaryColor;
final Color accentColor = Theme.of(context).accentColor;
return Column(
children: [
Text('test', style:TextStyle(color:primaryColor)),
Icon(Icons.arrow_drop_down, color: accentColor)
]
)
}
就像这样,任何控件在任何页面调用全局颜色。
但是,ThemeData里面的每一个属性都是用来修改Material里面大部分Widget的默认样式
比如,我们现在需要在一个页面加一个默认样式的TabBar
,直接这样写下就好
bottom: TabBar(
tabs: ['语文','英语',]
controller: _controller,
),
TabBar的颜色也成了设定的primaryColor颜色,当我们需要很多个默认颜色的时候,来配置ThemeData的默认颜色显然不是一种好的选择
3、最简单的方法
其实可以新建一个名为myStyle.dart的文件里面定义一个class,在其他的文件用更少的字符就可以直接进行引用,也不会影响控件的默认样式
// myStyle.dart
class MyColor {
static const Color mainColor = Color(0xFFEA1C1C);
static const Color secondColor = Color(0xFFFDCBC8);
static const Color thirdColor = Color(0xFFFEC650);
static const Color deepBlack = Color(0xFF010211);
static const Color lightBlack = Color(0xFFEA1C1C);
static const Color deepGrey = Color(0xFF65656E);
static const Color lightGrey = Color(0xFFD0D0D2);
}
// 其他页面
import 'package:app/utils/myStyle.dart';
Text('test', style:TextStyle(color:MyColor.mainColor)),
Icon(Icons.arrow_drop_down, color: MyColor.secondColor)
三、全局文字样式
全局颜色直接通过可以通过class进行配置,我们也可以用class配置全局字体样式
1、直接配置字号
// myStyle.dart
class MyFontSize {
static const int bigTitle = 32;
static const int mainTitle = 26;
static const int subTitle = 22;
static const int content = 16;
static const int annotation = 14;
static const int smallSize = 12;
}
这样配置好了,可进行直接引用,但一般的相同的位置,字号一样,颜色一样,字重肯定也一样
2、直接配置字体样式
// myStyle.dart
class MyFontStyle {
static const TextStyle bigTitle = TextStyle(color: Colors.black, fontSize: 32, fontWeight: FontWeight.bold);
static const TextStyle mainTitle = TextStyle(color: Colors.black87, fontSize: 26, fontWeight: FontWeight.w600);
static const TextStyle subTitle = TextStyle(color: Colors.black54, fontSize: 22, fontWeight: FontWeight.w400);
static const TextStyle content = TextStyle(color: Colors.black, fontSize: 16, fontWeight: FontWeight.normal);
static const TextStyle annotation = TextStyle(color: Colors.black38, fontSize: 14, fontWeight: FontWeight.normal);
static const TextStyle smallSize = TextStyle(color: Colors.black, fontSize: 12, fontWeight: FontWeight.normal);
}
那么还有一个问题,做移动端开发,尺寸大小根据屏幕自适应是必须要加的,我们可以通过flutter_screenutil
这个插件来完成这个工作
3、加入文字大小自适应
我们先在pubspec.yaml里面进行引入现在已经是flutter_screenutil 3.2.0
的版本了,这个插件已经有很多人写过使用方法,我们再简单的说一下, 有以下几点要注意
- 每个页面使用这个插件,都必须
ScreenUtil.init()
一遍- 这个插件依赖于
MediaQuery.of(context)
这个方法,而这个方法只能只能在Weight
里使用
我们在一般页面里可以直接引入并调用
import 'package:flutter_screenutil/flutter_screenutil.dart';
Widget build(BuildContext context) {
super.build(context);
ScreenUtil.init(context, designSize: Size(750, 1334), allowFontScaling: true);
return Scaffold(
// 新版本语法优化 32.sp = ScreenUtil().setWidth(32)
body: Text('test', testStyle(fontSize: 32.sp))
)
}
当我们想完成以下效果时,在main.dart
页面引入的时候,你会发现
// 初始化完成
Widget build(BuildContext context) {
ScreenUtil.init(context, designSize: Size(750, 1334), allowFontScaling: true);
return MaterialApp()
}
// 使用自适应值
TextStyle(color: Colors.black, fontSize: 32.sp, fontWeight: FontWeight.bold);
因为在初始化ScreenUtil.init()
方法的时候,需要调用MediaQuery.of()
方法,而在main.dart
这个页面,我们没办法在MaterialApp()
里面初始化这个方法,不进行初始化无法使用,为了这个方法,我们只能绕个圈子。
而且32.sp
相当于ScreenUtil().setWidth(32)
,这个方法也是只能在MaterialApp()
里面使用,所以只能通过下面方式进行实现
// 第一步: 建立一个WidgetsBindingObserver用来将MyApp()包含进去
class ScreenApp extends StatefulWidget {
@override
_ScreenAppState createState() => _ScreenAppState();
}
class _ScreenAppState extends State<ScreenApp> with WidgetsBindingObserver {
@override
Widget build(BuildContext context) {
ScreenUtil.init(context, designSize: Size(750, 1334), allowFontScaling: true);
return MyApp();
}
}
// 第二步: 建立一个监听APP状态改变的Widget,要求传入一个child
class MediaQueryFromWindow extends StatefulWidget {
//要求页面传入一个子控件
const MediaQueryFromWindow({
Key key,
@required this.child,
}): super(key: key);
final Widget child;
@override
_MediaQueryFromWindowState createState() => _MediaQueryFromWindowState();
}
// 当页面状态改变的时候,进行监听
class _MediaQueryFromWindowState extends State<MediaQueryFromWindow> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
Widget build(BuildContext context) {
//创建一个带有窗口数据的widget
return MediaQuery(
data: MediaQueryData.fromWindow(WidgetsBinding.instance.window),
child: widget.child,
);
}
}
// 第三步:将ScreenApp()传入MediaQueryFromWindow()
void main() {
return runApp(
MediaQueryFromWindow(child: ScreenApp()),
);
}
// 原始的页面
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '测试',
home: ()
);
}
}
将上面的字体样式修改为这样,flutter_screenutil
还是只能在Weight
里使用,所以
// myStyle.dart
class MyFontStyle extends StatelessWidget {
static const TextStyle bigTitle = TextStyle(color: Colors.black, fontSize: 32.sp, fontWeight: FontWeight.bold);
static const TextStyle mainTitle = TextStyle(color: Colors.black87, fontSize: 26.sp, fontWeight: FontWeight.w600);
static const TextStyle subTitle = TextStyle(color: Colors.black54, fontSize: 22.sp, fontWeight: FontWeight.w400);
static const TextStyle content = TextStyle(color: Colors.black, fontSize: 16.sp, fontWeight: FontWeight.normal);
static const TextStyle annotation = TextStyle(color: Colors.black38, fontSize: 14.sp, fontWeight: FontWeight.normal);
static const TextStyle smallSize = TextStyle(color: Colors.black, fontSize: 12.sp, fontWeight: FontWeight.normal);
@override
Widget build(BuildContext context) {
return Container();
}
}
// 其他页面
import 'package:app/utils/myStyle.dart';
Text('活动', style: MyFontStyle.h1)
四、总结
当UI颜色少的时候,使用ThemeData里面的属性,来做全局样式,其实问题不大, 我们一般都会为自己写的widget写上颜色属性,但颜色多的时候,将里面的属性都进行修改,反而会照成自己的麻烦,而且名字无法自定义,没有更好的语义化,用的时候也不方便,自己在main.dart
里面写一个class,全局都可以直接调用,更加方便灵活
我们一般使用flutter_screenutil
这个插件的时候,都是在普通的页面进行,使用起来非常方便,一般的盒子控件还好,但像标题,副标题,说明等每个页面都一样的字体样式,我们可以用全局来设定好,后期如果需要调整也更加方便。不过主页进行初始化有点小坑,解决了就不是很难,就是给MyApp()
再套一层MediaQuery
。
转载自:https://juejin.cn/post/6898775045099749384