likes
comments
collection
share

Flutter 全局颜色和全局字体样式

作者站长头像
站长
· 阅读数 25

一、前言


经常和UI打交道的前端开发者都明白,任何产品的视觉语言都需要统一。而这无外乎2个规范:字体规范 & 色彩规范。字体样式一般需要5~10种,色彩规范就很多了,但一般至少也需要5种以上,比如:

Flutter 全局颜色和全局字体样式

当我们在网上找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)
        ]
    )
}

Flutter 全局颜色和全局字体样式

就像这样,任何控件在任何页面调用全局颜色。

但是,ThemeData里面的每一个属性都是用来修改Material里面大部分Widget的默认样式

比如,我们现在需要在一个页面加一个默认样式的TabBar,直接这样写下就好

bottom: TabBar(
  tabs: ['语文','英语',]
  controller: _controller,
),

Flutter 全局颜色和全局字体样式

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)

Flutter 全局颜色和全局字体样式

三、全局文字样式

全局颜色直接通过可以通过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);

Flutter 全局颜色和全局字体样式

因为在初始化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
评论
请登录