Flutter全局与局部字体(全App、全页面、单控件的设置方法)

一、背景

项目里需要单独替换几个页面的字体。于是找到了全局指定字体的方法,参考文章:Flutter 指定字体(全局指定、局部指定),该文章提到了三种替换方法:

①全局替换,在MaterialApp的theme属性中,指定fontFamily。
②单个替换,单独在Text的style中指定fontFamily。
③多处替换,定义公共TextStyle ,调用它的copyWith方法。

为了方便理解,在此搬运一下:
1.全局配置— 就在主题theme中配置

MaterialApp(
  theme: ThemeData(
      fontFamily: "PingFang", // 统一指定应用的字体。
      primarySwatch: Colors.green,
      primaryColor: Colors.white),
      。。。

2.局部配置—指定TextStyle中的fontFamily

TextStyle(
    fontFamily:"PingFang", // 指定该Text的字体。
    fontSize: SizeUtil.getFontSize(Dimens.font_sp12),
    color: CustomColors.colorPrimary,
    fontWeight: FontWeight.bold)

3.如果多处用到指定的字体,但又不是全局用到, 你可以定义一个公共的 textStyle .如:

var textFontStyle  = TextStyle(
    fontFamily:"PingFang", // 指定该Text的字体。
)
 
用到的地方用 .copyWith 这个方法, 如: 
Text(
    "显示我想要的字体",
    style: textFontStyle.copyWith(
        fontSize: 18.0,
        color: Colors.red,
        fontWeight: FontWeight.bold,
        ),
    )

TextStyle的copyWith如下: 

 TextStyle copyWith({
    bool inherit,
    Color color,
    Color backgroundColor,
    String fontFamily,
    List<String> fontFamilyFallback,
    double fontSize,
    FontWeight fontWeight,
    FontStyle fontStyle,
    double letterSpacing,
    double wordSpacing,
    TextBaseline textBaseline,
    double height,
    Locale locale,
    Paint foreground,
    Paint background,
    List<ui.Shadow> shadows,
    TextDecoration decoration,
    Color decorationColor,
    TextDecorationStyle decorationStyle,
    double decorationThickness,
    String debugLabel,
  })

我们项目是需要替换几个页面,不是全App,第一种方法直接pass。第二种和第三种差不多,都是需要给每个Text控件设置字体,区别只是第三种不用每次指定字体名称。我们页面里面Text控件蛮多的,每个指定,也有较大的工作量。
那么,有没有单独指定某个页面的字体的方法呢?
以下是几种尝试:

二、验证后淘汰的方法

1、在页面外包裹Theme()控件(无效)

全局指定的方法很眼熟,那么直接在某一块控件外,包裹一个Theme控件,不就和在MaterialApp中指定的一样吗?想到这里,我不得不佩服我的机智,这么简单的方法,居然只被我一个人想出来!
于是我兴冲冲的去尝试了,在Column控件外包裹Theme,在Theme中指定字体,期待这整个Column控件都变成我指定的字体。代码如下:

@override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(
        fontFamily: "MaoTi",
      ),
      child: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              Text("12345"),
              Text("678910"),
            ],
          ),
        ],
      )
    );
  }

然而,该方法无效,Text的字体并没有随之改变!

2、在页面外包裹MaterialApp控件(某些全局设定会冲突)

MaterialApp也是一个控件,在整个页面外嵌套一层MaterialApp,然后在该MaterialApp的theme属性中设置fontFamily。代码如下:

@override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        fontFamily: "MaoTi",
      ),
      home: RealPage(),
    );
  }

该方法是有效的,字体确实改变了。不过,之前的一些全局配置,比如滑动控件的波纹效果、配置的首选颜色等,被MaterialApp层拦截了,页面中使用的是Flutter默认的MaterialApp配置,没有使用整个App入口指定的配置。需要把这些全局配置重新指定一遍,才能达到一致的效果。

三、正确的使用方式

3.在Scaffold外包裹Theme控件

为啥在MaterialApp的theme指定有效,直接在控件外包裹Theme控件却无效了?我感到很奇怪。查看源码,源码里也是直接用Theme包裹着child控件啊?真是太神奇了!
我注释掉部分代码,希望找到让Text字体生效的控件,经过fromwork层绕了一圈,发现生效的控件居然不在fromwork层,而是从外面传进去的!!!又经过一番排查,终于锁定,令theme生效的控件是Scaffold。
验证发现,字体是否生效与MaterialApp没有半毛钱关系,只与Scaffold有关。而Scaffold几乎是每个页面都有的,在它外层包裹Theme,指定fontFamily,即可达到单独设置某个页面的效果。而且,它不会阻隔MaterialApp中指定的全局配置,完美!

@override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(
        fontFamily: "MaoTi",
      ),
      child: Scaffold(
          body:
          Column(
            children: <Widget>[
              Row(
                children: <Widget>[
                  Text("12345"),
                  Text("678910"),
                ],
              ),
            ],
          )
      ),
    );
  }

四、依然存在的坑

Theme结合Scaffold,能指定页面级别的Text控件字体。但是,如果页面中有使用富文本,或者自定义的Text控件,字体不会生效,还得在style中单独设置。在MaterialApp的theme属性中指定fontFamily,同样会有这个问题。因为字体只和Scaffold有关,和MaterialApp没有关系。

@override
  Widget build(BuildContext context) {
    return Theme(
      data: ThemeData(
        fontFamily: "MaoTi",
      ),
      child: Scaffold(
          body:
          Center(child: Column(
            children: <Widget>[
              Row(
                children: <Widget>[
                  // 富文本,ThemeData中的指定无效,需在TextStyle中单独指定
                  RichText(
                      text: TextSpan(
                          text: "123456",
                        style: TextStyle(color: Colors.blue,fontSize: 30,fontFamily: "MaoTi",)
                      )),
                  // 自定义文本,同上。能不能通过改变自定义方法来使用Theme字体不太清楚,我们项目中的自定义字体需单独指定
                  CustomText("123456",style: TextStyle(color: Colors.red,fontFamily: "MaoTi",),)
                ],
              ),
            ],
          )
          )
      ),
    );
  }

五、总结

字体的指定,从大到小,目前有以下几种方法:

①全App,在MateralApp中指定,只要每个页面都有Scaffold,需注意一下富文本和自定义文本。
②全页面,Theme结合Scaffold使用,同样需注意富文本和自定义文本。
③多处使用,定义公共TextStyle,调用copyWith方法。
④单个控件,直接在TextStyle中设置fontFamily。

技术是在不断发展的,我当前使用的版本是1.9,或许后面高的版本会有更多的使用方法,又或者现在我遇到的问题在高版本并不会用到,这篇文章只能提供一个思路,给大家参考,感谢阅读!
最后,也谢谢@emdd2016大大,他的文章给我指了一个验证的方向。本文只提供了使用字体的方法,引入字体的方法网上太多,不再赘述,可以自行查找。

参考文章:https://blog.csdn.net/emdd2016/article/details/93312143

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值