Flutter自定义原生字体插件native_font的使用

发布于 1周前 作者 bupafengyu 来自 Flutter

Flutter自定义原生字体插件native_font的使用

native_font 是一个Flutter插件,用于从本地端懒加载字体文件(支持ttf和otf格式)。其代码灵感来源于 google_fonts

安装

要在项目中使用此插件,请在 pubspec.yaml 文件中添加 native_font 作为依赖项。

dependencies:
  native_font: <latest version>

请确保将 <latest version> 替换为最新版本号。

使用

iOS 设置

在 Swift 中:

NativeFontPlugin.fontDataHandler = { (familyName, weight, isItalic, callback) in
  if familyName == "Roboto" {
    var fileName = "Roboto-Regular.ttf"
    if weight == FlutterFontWeight.weight700 {
      fileName = isItalic ? "Roboto-BoldItalic.ttf" : "Roboto-Bold.ttf"
    } else if weight == FlutterFontWeight.weight400 {
      fileName = isItalic ? "Roboto-Italic.ttf" : "Roboto-Regular.ttf"
    } else if weight == FlutterFontWeight.weight500 {
      fileName = "Roboto-Medium.ttf"
    }
    callback(try! Data(contentsOf: Bundle.main.url(forResource: fileName, withExtension: nil)!))
  } else if familyName == "Caveat" {
    // ...
  }
}

在 Objective-C 中:

NativeFontPlugin.fontDataHandler = ^(NSString * _Nonnull familyName, FlutterFontWeight weight, BOOL isItalic, void (^ _Nonnull callback)(NSData * _Nullable)) {
  if ([familyName isEqualToString:@"Roboto"]) {
    NSString *fileName = @"Roboto-Regular.ttf";
    if (weight == FlutterFontWeight700) {
        fileName = isItalic ? @"Roboto-BoldItalic.ttf" : @"Roboto-Bold.ttf";
    } else if (weight == FlutterFontWeight400) {
        fileName = isItalic ? @"Roboto-Italic.ttf" : @"Roboto-Regular.ttf";
    } else if (weight == FlutterFontWeight500) {
        fileName = @"Roboto-Medium.ttf";
    }
    callback([NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:fileName ofType:nil]]);
  } else if ([familyName isEqualToString:@"Caveat"]) {
    // ...
  }
};

Android 设置

NativeFontPlugin.setFontDataHandler((familyName, fontWeight, isItalic, fontCallBack) -> {
  if (familyName.equals("Roboto")) {
    int familyId = R.font.roboto_regular;
    if (fontWeight == FontStyle.FONT_WEIGHT_BOLD) {
        familyId = isItalic ? R.font.roboto_bold_italic : R.font.roboto_bold;
    } else if (fontWeight == FontStyle.FONT_WEIGHT_NORMAL) {
        familyId = isItalic ? R.font.roboto_italic : R.font.roboto_regular;
    } else if (fontWeight == FontStyle.FONT_WEIGHT_MEDIUM) {
        familyId = R.font.roboto_medium;
    }
    fontCallBack.onFontLoadCompleted(fontResToByteBuffer(familyId));
  } else if (familyName.equals("Caveat")) {
    // ...
  }
});

Flutter 端使用示例

import 'package:flutter/material.dart';
import 'package:native_font/native_font.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Native Fonts'),
        ),
        body: Column(
          children: <Widget>[
            Text(
              'Caveat (Download in native after 3s)',
              style: nativeFontTextStyle(
                fontFamily: 'Caveat',
                fontSize: 30,
              ),
            ),
            Text(
              'Roboto',
              style: nativeFontTextStyle(
                fontFamily: 'Roboto',
                fontSize: 30,
              ),
            ),
            Text(
              'Roboto Italic',
              style: nativeFontTextStyle(
                fontFamily: 'Roboto',
                fontSize: 30,
                fontStyle: FontStyle.italic,
              ),
            ),
            Text(
              'Roboto Medium',
              style: nativeFontTextStyle(
                fontFamily: 'Roboto',
                fontSize: 30,
                fontWeight: FontWeight.w500,
              ),
            ),
            Text(
              'Roboto Bold',
              style: nativeFontTextStyle(
                fontFamily: 'Roboto',
                fontSize: 30,
                fontWeight: FontWeight.w700,
              ),
            ),
            Text(
              'Roboto Bold Italic',
              style: nativeFontTextStyle(
                fontFamily: 'Roboto',
                fontSize: 30,
                fontWeight: FontWeight.w700,
                fontStyle: FontStyle.italic,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

注意事项

关于字体粗细

字体通常使用100~900之间的九阶有序值来划分其粗细(字体的厚度),其中normal等同于400,bold等同于700。许多情况下,一些通用的词描述被用来划分它们的粗细。常见的粗细值大致对应如下:

  • 100 - Thin
  • 200 - Extra Light (Ultra Light)
  • 300 - Light
  • 400 - Regular (Normal、Book、Roman)
  • 500 - Medium
  • 600 - Semi Bold (Demi Bold)
  • 700 - Bold
  • 800 - Extra Bold (Ultra Bold)
  • 900 - Black (Heavy)

这些词汇通常包含在常规字体文件的命名中。

回退机制

当Flutter端使用的字体在本地端未注册或回调的字体数据无法正确加载时,会回退到默认字体,并且文本始终会被显示。

异步加载

得益于强大的 FontLoader 功能,当字体数据通过回调返回给Flutter端时,文本将自动刷新。


更多关于Flutter自定义原生字体插件native_font的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义原生字体插件native_font的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用自定义原生字体插件native_font的一个详细代码示例。这个示例将展示如何在iOS和Android平台上集成和使用native_font插件来加载和使用自定义字体。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加native_font依赖:

dependencies:
  flutter:
    sdk: flutter
  native_font: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

2. 准备自定义字体文件

将你的自定义字体文件(例如MyCustomFont.ttf)放在assets/fonts/目录下。确保在pubspec.yaml中声明这些字体文件为资产:

flutter:
  assets:
    - assets/fonts/MyCustomFont.ttf

3. 配置原生代码

iOS

对于iOS,你需要在Info.plist中添加字体文件信息。不过,由于native_font插件内部处理了很多配置,通常不需要手动修改Info.plist。不过,确保字体文件已经被正确复制到Xcode项目的资源中。

Android

对于Android,你需要在android/app/src/main/assets/fonts/目录下放置你的字体文件(与Flutter项目的assets/fonts/目录相对应)。通常,native_font插件也会处理这部分配置,但确保字体文件位置正确是很重要的。

4. 使用native_font插件

在你的Flutter代码中,你可以这样使用native_font插件来加载和应用自定义字体:

import 'package:flutter/material.dart';
import 'package:native_font/native_font.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Native Font Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late NativeFont? _nativeFont;

  @override
  void initState() {
    super.initState();
    _loadNativeFont();
  }

  Future<void> _loadNativeFont() async {
    try {
      // 加载自定义字体
      _nativeFont = await NativeFont.load('assets/fonts/MyCustomFont.ttf');
      // 应用字体到TextTheme(可选)
      final TextTheme customTextTheme = Theme.of(context).textTheme.copyWith(
        bodyText1: TextStyle(fontFamily: _nativeFont!.fontFamily, fontSize: 16),
      );
      // 更新主题(可选,如果你想要全局应用)
      // 注意:这里只是示例,实际使用中你可能需要更复杂的逻辑来更新主题
      // 例如使用Provider或其他状态管理库
      // Provider.of<ThemeNotifier>(context, listen: false).updateTheme(
      //   theme: ThemeData(textTheme: customTextTheme),
      // );
    } catch (e) {
      print('Failed to load native font: $e');
    }

    // 如果只需要局部应用字体,可以在build方法中直接使用
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Native Font Example'),
      ),
      body: Center(
        child: _nativeFont != null
            ? Text(
                'Hello, this is a text with custom native font!',
                style: TextStyle(fontFamily: _nativeFont!.fontFamily, fontSize: 24),
              )
            : CircularProgressIndicator(), // 加载中显示加载指示器
      ),
    );
  }
}

在这个示例中,我们首先通过NativeFont.load方法异步加载自定义字体文件。加载成功后,我们创建一个TextStyle实例,并将其fontFamily属性设置为加载的字体名称(通过_nativeFont!.fontFamily获取)。然后,我们在Text控件中使用这个TextStyle来显示带有自定义字体的文本。

注意:实际项目中,你可能需要更复杂的逻辑来处理字体加载和主题更新,特别是当你需要在整个应用中全局应用自定义字体时。这里提供的代码只是一个简单的示例,展示了如何加载和应用自定义字体。

回到顶部