Flutter自动生成代码插件ds_flutter_gen_core的使用

Flutter自动生成代码插件ds_flutter_gen_core的使用


Logo

Pub Build Status Coverage

ds_flutter_gen_core 是一个用于自动生成 Flutter 项目代码的插件。通过该插件,你可以自动为你的项目中的资源(如资产文件、字体、颜色等)生成对应的 Dart 类,从而避免直接使用字符串路径带来的潜在错误。


动机

直接使用字符串路径引用资源文件是不安全的。例如,在 pubspec.yaml 文件中配置了某个图像文件:

flutter:
  assets:
    - assets/images/profile.jpg

如果在引用时出现拼写错误:

Widget build(BuildContext context) {
  return Image.asset('assets/images/profile.jpeg');
}

// The following assertion was thrown resolving an image codec:
// Unable to load asset: assets/images/profile.jpeg

为了避免这类问题,我们可以使用 ds_flutter_gen_core 自动生成的类来引用资源文件:

Widget build(BuildContext context) {
  return Assets.images.profile.image();
}

安装过程

Pub Global

适用于 macOS、Linux 和 Windows。

dart pub global activate ds_flutter_gen

你可能需要设置你的环境变量路径:

export PATH="$PATH:$HOME/.pub-cache/bin"

作为 build_runner 的一部分

  1. pubspec.yaml 中添加依赖项:
dev_dependencies:
  build_runner:
  ds_flutter_gen_runner:
  1. 运行 flutter pub get 来安装依赖项:
flutter pub get
  1. 使用 build_runner 生成代码:
dart run build_runner build

使用方法

运行 fluttergen 命令来生成代码:

fluttergen -h

fluttergen -c example/pubspec.yaml

配置文件

ds_flutter_gen_core 会基于 pubspec.yaml 文件中的 flutterds_flutter_gen 键生成 Dart 文件。

# pubspec.yaml
# ...

ds_flutter_gen:
  output: lib/gen/ # 可选,默认值为 lib/gen/
  line_length: 80 # 可选,默认值为 80

  # 可选
  integrations:
    flutter_svg: true
    flare_flutter: true
    rive: true
    lottie: true

flutter:
  uses-material-design: true
  assets:
    - assets/images/

  fonts:
    - family: Raleway
      fonts:
        - asset: assets/fonts/Raleway-Regular.ttf
        - asset: assets/fonts/Raleway-Italic.ttf
          style: italic

build.yaml

你也可以在 build.yaml 文件中配置生成选项,它将优先于 pubspec.yaml 文件。

# build.yaml
# ...

targets:
  $default:
    builders:
      ds_flutter_gen_runner: # 或者 flutter_gen
        options: 
          output: lib/build_gen/ # 可选,默认值为 lib/gen/
          line_length: 120 # 可选,默认值为 80

可用解析器

资源文件

根据文档指定资源文件后,ds_flutter_gen_core 将生成相关的 Dart 文件。无需其他特定配置。

# pubspec.yaml
flutter:
  assets:
    - assets/images/
    - assets/images/chip3/chip.jpg
    - assets/images/chip4/chip.jpg
    - assets/images/icons/paint.svg
    - assets/images/icons/dart@test.svg
    - assets/json/fruits.json
    - assets/flare/Penguin.flr
    - assets/rive/vehicles.riv
    - pictures/ocean_view.jpg

这些配置将在默认情况下生成 lib/gen/assets.gen.dart 文件。

生成 flavored 资源

如果你需要根据不同的风味生成资源,ds_flutter_gen_core 会生成相应的 flavors 字段。

print(MyAssets.images.chip4.flavors); // -> {'extern'}

排除生成某些资源

你可以使用 Glob 模式来排除特定的资源。

ds_flutter_gen:
  assets:
    exclude:
      - folder-your-want-to-exclude/**
      - specified-asset.jpg

为包生成资源

如果你希望为包生成资源,可以启用 package_parameter_enabled

ds_flutter_gen:
  assets:
    outputs:
      package_parameter_enabled: true # <- 添加此行。

生成目录路径

如果你希望生成目录路径,可以启用 directory_path_enabled

ds_flutter_gen:
  assets:
    outputs:
      directory_path_enabled: true # <- 添加此行。

包含额外元数据

在构建时,你可以包含额外的元数据。

ds_flutter_gen:
  parse_metadata: true # <- 添加此行(默认值为 false)

使用示例

ds_flutter_gen_core 会生成 Image 类,如果资产文件是 Flutter 支持的图像格式。

Widget build(BuildContext context) {
  return Assets.images.chip.image();
}

Widget build(BuildContext context) {
  return Assets.images.chip.image(
    width: 120,
    height: 120,
    fit: BoxFit.scaleDown,
  );

Widget build(BuildContext context) {
  // Assets.images.chip.path = 'assets/images/chip3/chip3.jpg'
  return Image.asset(Assets.images.chip.path);
}

如果使用 flutter_svg 处理 SVG 图像,可以使用集成特性。

# pubspec.yaml
ds_flutter_gen:
  integrations:
    flutter_svg: true

flutter:
  assets:
    - assets/images/icons/paint.svg
Widget build(BuildContext context) {
  return Assets.images.icons.paint.svg(
    width: 120,
    height: 120
  );
}

可用集成

插件 文件扩展名 设置 使用
flutter_svg .svg flutter_svg: true Assets.images.icons.paint.svg()
flare_flutter .flr flare_flutter: true Assets.flare.penguin.flare()
rive .flr rive: true Assets.rive.vehicles.rive()
lottie .json, .zip lottie: true Assets.lottie.hamburgerArrow.lottie()

在其他情况下,资产将被生成为 String 类。

// 如果不使用集成。
final svg = SvgPicture.asset(Assets.images.icons.paint);

final json = await rootBundle.loadString(Assets.json.fruits);

ds_flutter_gen_core 还支持生成其他样式的 Assets 类。

# pubspec.yaml
ds_flutter_gen:
  assets:
    outputs: 
      # Assets.imagesChip
      # style: camel-case

      # Assets.images_chip
      # style: snake-case

      # Assets.images.chip (默认样式)
      # style: dot-delimiter

flutter:
  assets:
    - assets/images/chip.png

根目录将被省略,如果它是 assetsasset

assets/images/chip3/chip.jpg      => Assets.images.chip3.chip
assets/images/chip4/chip.jpg      => Assets.images.chip4.chip
assets/images/icons/paint.svg     => Assets.images.icons.paint
assets/images/icons/dart@test.svg => Assets.images.icons.dartTest
assets/json/fruits.json           => Assets.json.fruits
pictures/ocean_view.jpg           => Assets.pictures.oceanView

字体

遵循文档指定字体,然后 ds_flutter_gen_core 将生成相关的 Dart 文件。

# pubspec.yaml
flutter:
  fonts:
    - family: Raleway
      fonts:
        - asset: assets/fonts/Raleway-Regular.ttf
        - asset: assets/fonts/Raleway-Italic.ttf
          style: italic
    - family: RobotoMono
      fonts:
        - asset: assets/fonts/RobotoMono-Regular.ttf
        - asset: assets/fonts/RobotoMono-Bold.ttf
          weight: 700

这些配置将在默认情况下生成 lib/gen/fonts.gen.dart 文件。

为包生成字体

如果你希望为包生成字体,可以启用 package_parameter_enabled

ds_flutter_gen:
  fonts:
    outputs:
      package_parameter_enabled: true # <- 添加此行。

这将向生成的类中添加包常量。例如:

class Fonts {
  Fonts._();

  static const String package = 'test';

  static const String raleway = 'packages/$package/Raleway';
  static const String robotoMono = 'packages/$package/RobotoMono';
}

使用示例

Text(
  'Hi there, I\'m FlutterGen',
  style: TextStyle(
    fontFamily: FontFamily.robotoMono,
    fontFamilyFallback: const [FontFamily.raleway],
  ),
)

颜色

ds_flutter_gen_core 支持从 XML 格式的文件生成颜色。

# pubspec.yaml
ds_flutter_gen:
  colors:
    inputs:
      - assets/color/colors.xml
      - assets/color/colors2.xml

ds_flutter_gen_core 可以根据 name 属性和颜色十六进制值生成 Color 类。如果元素具有 type 属性,则会生成特殊颜色。

当前支持的特殊颜色类型:

  • MaterialColor
  • MaterialAccentColor
<color name="milk_tea">#F5CB84</color>
<color name="cinnamon" type="material">#955E1C</color>
<color name="yellow_ocher" type="material material-accent">#DF9527</color>

这些配置将在默认情况下生成 lib/gen/colors.gen.dart 文件。

使用示例

Text(
  'Hi there, I\'m FlutterGen',
  style: TextStyle(
    color: ColorName.denim,
  ),
)

已知问题

Bad State: No Element when using build_runner

如果你遇到这样的错误信息:

[SEVERE] flutter_gen_runner:flutter_gen_runner on $package$:

Bad state: No element
[SEVERE] Failed after 16.0s

则最有可能是因为你有一个自定义的 build.yaml 文件来配置 build_runner。在这种情况下,只需将 pubspec.yaml 添加到 build.yamlsources 部分即可。

targets:
  $default:
    sources:
      include:
        - pubspec.yaml  # 添加此行
        - ...

示例代码

import 'package:example_resources/gen/assets.gen.dart';
import 'package:flutter/material.dart';

import 'gen/assets.gen.dart';
import 'gen/colors.gen.dart';
import 'gen/fonts.gen.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // await Firebase.initializeApp(
  //   options: DefaultFirebaseOptions.currentPlatform,
  // );

  runApp(MaterialApp(
    title: 'Flutter Demo',
    theme: ThemeData(
      // 自动生成的字体来自 FlutterGen。
      fontFamily: MyFontFamily.raleway,
      primarySwatch: MyColorName.crimsonRed,
    ),
    home: Scaffold(
      appBar: AppBar(
        title: const Text('FlutterGen'),
      ),
      body: Center(
        child: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              // 自动生成的图像来自 FlutterGen。
              SizedBox(
                width: 200,
                height: 200,
                child: MyAssets.flare.penguin.flare(
                  animation: 'walk',
                  fit: BoxFit.contain,
                ),
              ),
              SizedBox(
                width: 200,
                height: 200,
                child: MyAssets.rive.vehicles.rive(
                  fit: BoxFit.contain,
                ),
              ),
              SizedBox(
                width: 200,
                height: 200,
                child: MyAssets.lottie.hamburgerArrow.lottie(
                  fit: BoxFit.contain,
                ),
              ),
              SizedBox(
                width: 200,
                height: 200,
                child: MyAssets.lottie.geometricalAnimation.lottie(
                  fit: BoxFit.contain,
                ),
              ),
              SizedBox(
                width: 200,
                height: 200,
                child: MyAssets.lottie.alarmClockLottieV440.lottie(
                  fit: BoxFit.contain,
                ),
              ),
              MyAssets.images.chip1.image(),
              Container(
                height: 400,
                decoration: BoxDecoration(
                  image: DecorationImage(
                    image: MyAssets.images.chip1.provider(),
                  ),
                ),
                child: const Center(child: Text('Deco')),
              ),
              // 使用 example_resource 包。
              MyAssets.images.icons.kmm.svg(key: const Key('kmm_svg')),
              MyAssets.images.icons.fuchsia.svg(),
              MyAssets.images.icons.paint.svg(
                width: 120,
                height: 120,
              ),
              // MyAssets.pictures.chip5.image(
              //   key: const Key("chip5"),
              //   width: 120,
              //   height: 120,
              //   fit: BoxFit.scaleDown,
              // ),

              // example_resource 包。
              Text(MyAssets.images.icons.kmm.path),
              Text(MyAssets.images.icons.kmm.keyName),
              Text(ResAssets.images.dart.path),
              Text(ResAssets.images.dart.keyName),
              ResAssets.images.flutter3.image(),
              ResAssets.images.dart.svg(),
              SizedBox(
                width: 200,
                height: 200,
                child: ResAssets.images.skills.rive(
                  fit: BoxFit.contain,
                ),
              ),
              SizedBox(
                width: 200,
                height: 200,
                child: ResAssets.images.favorite.flare(
                  shouldClip: false,
                ),
              ),
              SizedBox(
                width: 200,
                height: 200,
                child: ResAssets.images.runningCarOnRoad.lottie(
                  fit: BoxFit.contain,
                ),
              ),
              const Text(
                'Hi there, I\'m FlutterGen',
                style: TextStyle(
                  // 自动生成的颜色来自 FlutterGen。
                  color: MyColorName.black60,

                  // 自动生成的字体来自 FlutterGen。
                  fontFamily: MyFontFamily.robotoMono,
                  fontFamilyFallback: [MyFontFamily.raleway],
                ),
              ),
            ],
          ),
        ),
      ),
    ),
  ));
}

更多关于Flutter自动生成代码插件ds_flutter_gen_core的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自动生成代码插件ds_flutter_gen_core的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


ds_flutter_gen_core 是一个用于自动生成 Flutter 代码的插件,它可以帮助开发者通过注解和代码生成的方式减少重复代码的编写。使用这个插件,你可以通过定义一些注解,然后让插件自动生成相关的代码,如路由、序列化、依赖注入等。

安装步骤

  1. 添加依赖
    在你的 pubspec.yaml 文件中添加 ds_flutter_gen_corebuild_runner 依赖:

    dependencies:
      ds_flutter_gen_core: ^版本号
    
    dev_dependencies:
      build_runner: ^版本号
    

    请确保将 ^版本号 替换为实际的版本号。

  2. 创建注解
    你可以定义自己的注解类。例如,定义一个用于生成路由的注解:

    import 'package:ds_flutter_gen_core/ds_flutter_gen_core.dart';
    
    class RouteAnnotation {
      final String path;
    
      const RouteAnnotation(this.path);
    }
    
  3. 使用注解
    在你的代码中使用定义的注解。例如,在一个 Widget 上使用 RouteAnnotation

    [@RouteAnnotation](/user/RouteAnnotation)('/home')
    class HomeScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Home'),
          ),
          body: Center(
            child: Text('Welcome to the Home Screen!'),
          ),
        );
      }
    }
    
  4. 生成代码
    使用 build_runner 来生成代码。在终端中运行以下命令:

    flutter pub run build_runner build
    

    这将根据你定义的注解自动生成相关的代码。

示例:生成路由

假设你想生成路由相关的代码,你可以按照以下步骤操作:

  1. 定义路由注解
    定义一个 RouteAnnotation 类,如前所述。

  2. 生成路由代码
    使用 ds_flutter_gen_core 提供的代码生成器来生成路由代码。你可以在 lib 目录下创建一个 routes.dart 文件,并在其中生成路由映射。

    import 'package:flutter/material.dart';
    import 'package:ds_flutter_gen_core/ds_flutter_gen_core.dart';
    
    part 'routes.g.dart';
    
    [@RouteGenerator](/user/RouteGenerator)()
    class AppRoutes {
      static const String home = '/home';
    }
    
    Map<String, WidgetBuilder> get routes => _$routes;
    
  3. 运行代码生成器
    运行 flutter pub run build_runner buildds_flutter_gen_core 将会生成 routes.g.dart 文件,其中包含路由映射。

  4. 使用生成的路由
    在你的 main.dart 中使用生成的路由:

    import 'package:flutter/material.dart';
    import 'routes.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          initialRoute: AppRoutes.home,
          routes: routes,
        );
      }
    }
回到顶部