Flutter注解插件union_annotation的使用

Flutter注解插件union_annotation的使用

union_annotation 是一个允许为联合类型生成实用工具代码的包。生成器会为现有的类层次结构创建实用工具,而不会引入额外的类型到现有代码中。

快速开始

首先,在你的项目中添加所需的依赖项:

dependencies:
  union_annotation:

dev_dependencies:
  build_runner:
  union_generator:

然后运行以下命令来获取依赖项:

flutter pub get

接下来,使用可用的 Union 注解:

@Union.of(
  types: {
    Cat,
    Dog,
  },
)
abstract class Animal {}

之后,生成代码:

flutter pub run build_runner build

最后,你可以使用生成的实用工具:

void fun(Animal animal) {
  animal.map(
    cat: (cat) {},
    dog: (dog) {},
  );
}

注解

你可以为想要制作联合类型的现有类添加注解,并声明所有应被视为联合情况的类型:

@Union.of(
  types: {
    Cat,
    Dog,
  },
)
abstract class Animal {}

class Cat implements Animal {}

class Dog extends Animal {}

在类上添加注解将生成一个扩展,该扩展包含在 Animal 类上的实用方法:

animal.map(
  cat: (cat) {
    // 这是一只猫。
  },
  dog: (dog) {
    // 肯定是一只狗。
  },
);

如果所有联合子类型和联合本身都在同一文件中声明,则可以省略 types 参数(假定所有子类型都是联合的类型):

@Union.of()
abstract class Animal {}

class Cat implements Animal {}

class Dog extends Animal {}

还可以使用允许自定义生成代码的扩展版本注解:

@Union.ofCases({
  TypeCase(type: Cat, name: 'Cate'),
  TypeCase(type: Dog, name: 'Doge'),
})
abstract class Animal {}

枚举

你可以注解现有的枚举以为其添加联合功能,以便能够像操作普通类一样操作该枚举:

@Union.ofEnum()
enum Animal {
  cat,
  dog,
}

在枚举上添加注解将生成一个扩展,该扩展包含在 Animal 枚举上的类似实用方法:

animal.map(
  cat: () {
    // 这是一只猫。
  },
  dog: () {
    // 肯定是一只狗。
  },
);

还可以使用允许自定义生成代码的扩展版本注解:

@Union.ofEnumCases({
  EnumCase(value: Animal.cat, name: 'cate'),
  EnumCase(value: Animal.dog, name: 'doge'),
})
enum Animal {
  cat,
  dog,
}

常见配置选项

你可以为任何联合类型定义以下配置选项:

  • paramsType - 定义生成的实用工具所使用的参数类型(默认为 UnionParamsType.named):
@Union.of(
  types: {
    Cat,
    Dog,
  },
  paramsType: UnionParamsType.positional,
)
abstract class Animal {}

生成的所有联合实用工具都将使用位置参数:

animal.map(
  (cat) {
    // 这是一只猫。
  },
  (dog) {
    // 肯定是一只狗。
  },
);
  • utilities - 定义应为注解的联合生成哪些实用工具(默认为 UnionUtilities.all):
@Union.of(
  types: {
    Cat,
    Dog,
  },
  utilities: UnionUtilities.only(
    map: true,
    asType: true,
  ),
)
abstract class Animal {}

注解将仅生成 map 方法和 as*Type* 获取器。

注解外部类型

如果无法直接在联合类型上放置联合注解(例如,当类型在不同的包中声明时),可以在类型上创建一个扩展并注解该扩展:

@Union.of(
  types: {
    Cat,
    Dog,
  },
)
extension on Animal {}

实用工具

map

一个方法,它通过根据联合的实际类型运行提供的函数之一来转换联合对象为不同的类型。

mapOrNull

一个类似于 map 的方法,允许仅提供选定的函数。如果没有为联合情况提供函数,则返回 null

maybeMap

一个类似于 map 的方法,允许仅提供选定的函数。如果没有为联合情况提供函数,则返回 orElse 函数的结果。

asType

一个方法,它将联合对象强制转换为特定类型。如果实际类型与请求的不同,则抛出运行时错误。

asTypeOrNull

一个类似于 as*Type* 的方法,如果实际联合类型与请求的不同,则返回 null

构建选项

可以通过 build.yaml 文件修改生成器使用的默认值。以下是可配置的可用选项列表:

options:
  # 修改 UnionParamsType
  params_type:
  # 修改 UnionUtilities
  utilities:
    map:
    map_or_null:
    maybe_map:
    as_type:
    as_type_or_null:

例如,build.yaml 配置可能如下所示:

targets:
  $default:
    builders:
      union_generator:
        options:
          params_type: positional
          utilities:
            map: false
            map_or_null: true
            maybe_map: false
            as_type: true
            as_type_or_null: false

完整示例代码

以下是一个完整的示例代码,展示了如何使用 union_annotation 包:

import 'animal/animal.dart';
import 'animal/bear.dart';
import 'animal/bird.dart';
import 'animal/cat.dart';
import 'animal/dog_union.dart';
import 'animal/fish.dart';
import 'animal/flightless_union.dart';
import 'animal/horse.dart';
import 'animal/reptile.dart';

void main() {
  print(describe(Cat()));
}

String describe(Animal animal) {
  final type =
      animal is Enum ? (animal as Enum).name.capitalize() : animal.runtimeType;

  final info = animal.map(
    cat: (cat) => 'Lives: ${cat.lives}',
    dog: (dog) => dog.map(
      beagle: (beagle) => 'Age: ${beagle.age}',
      goldenRetriever: (goldenRetriever) =>
          'Friendly: ${goldenRetriever.friendly}',
      borderCollie: (borderCollie) => 'Sound: ${borderCollie.sound}',
    ),
    fish: (fish) => fish.map(
      jaws: (jaws) => 'Does shark eat humans: ${jaws.eatsHumans}',
      nemo: (nemo) => 'Does goldfish humans: ${nemo.eatsHumans}',
      piranha: (piranha) => 'Does piranha eat humans: ${piranha.eatsHumans}',
    ),
    reptile: (reptile) => reptile.map(
      lizard: () => '🦎',
      snake: () => '🐍',
      turtle: () => '🐢',
    ),
    bird: (bird) => bird.map(
      eagle: (eagle) => 'Wings color: ${eagle.wingsColor}',
      flightless: (flightless) => flightless.map(
        chicken: () => 'Tastes nice',
        emu: () => 'Quite fast',
        kiwi: () => 'Smol',
      ),
    ),
    horse: (horse) => horse.map(
      andy: () => '🐴 Andy',
      shawn: () => '🐴 Shawn',
      bob: () => '🐴 Bob',
    ),
    bear: (bear) => bear.map(
      polarBear: (polarBear) => 'White and huge',
      grizzlyBear: (grizzlyBear) => 'Brown and dangerous',
      blackBear: (blackBear) => 'Small but dangerous',
      pandaBear: (pandaBear) => 'Nice and cute',
    ),
  );

  return '$type > $info';
}

extension on String {
  String capitalize() {
    if (isEmpty) return '';
    return this[0].toUpperCase() + substring(1);
  }
}

更多关于Flutter注解插件union_annotation的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter注解插件union_annotation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,我可以为你提供一个关于如何在Flutter项目中使用union_annotation插件的代码示例。union_annotation通常用于与union相关的插件或框架,比如flutter_boost,它允许在不同Flutter页面或原生页面之间进行高效导航。

首先,确保你已经在pubspec.yaml文件中添加了union_annotation依赖:

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

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

接下来,我们将展示如何使用这个注解插件。假设你正在使用flutter_boost,并且需要在Flutter页面之间传递数据,你可以通过定义路由注解来实现。

1. 定义路由注解

首先,你需要定义一个路由注解类,该类将使用union_annotation提供的注解。

import 'package:union_annotation/union_annotation.dart';

@UnionRouteConfig(
  name: 'SecondPage',
  path: '/second',
  description: 'This is the second page route.',
)
class SecondPageRouteArgs {
  final String message;

  SecondPageRouteArgs({required this.message});

  // ToJson is required for serialization
  Map<String, dynamic> toJson() {
    return {
      'message': message,
    };
  }

  // Factory method to deserialize from JSON
  factory SecondPageRouteArgs.fromJson(Map<String, dynamic> json) {
    return SecondPageRouteArgs(
      message: json['message'] as String,
    );
  }
}

2. 创建页面并处理路由参数

接下来,创建一个页面组件,该组件将处理从路由传递过来的参数。

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'second_page_route_args.dart';  // 导入你定义的路由参数类

class SecondPage extends StatelessWidget {
  final SecondPageRouteArgs args;

  SecondPage({required this.args});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Second Page'),
      ),
      body: Center(
        child: Text('Message from First Page: ${args.message}'),
      ),
    );
  }
}

3. 在FlutterBoost中注册路由

如果你使用的是flutter_boost,你需要在初始化时注册这个路由。

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'second_page.dart';
import 'second_page_route_args.dart';

void main() {
  FlutterBoost.singleton
    ..addPages(<FlutterBoostPage>[
      FlutterBoostPage(
        name: 'SecondPage',
        pageBuilder: (_, __, args) {
          // Deserialize route arguments
          final routeArgs = SecondPageRouteArgs.fromJson(args as Map<String, dynamic>);
          return SecondPage(args: routeArgs);
        },
      ),
      // ... other pages
    ])
    ..init();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: FirstPage(),  // Assume you have a FirstPage widget
    );
  }
}

4. 从第一个页面跳转到第二个页面

最后,在第一个页面中,你可以使用FlutterBoost.singleton.openPage方法来打开第二个页面,并传递参数。

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'second_page_route_args.dart';

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('First Page'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            final routeArgs = SecondPageRouteArgs(message: 'Hello from First Page!');
            FlutterBoost.singleton
              .openPageByName(
                pageName: 'SecondPage',
                parameters: routeArgs.toJson(),
                // other options
              )
              .then((result) {
                // Handle result if needed
              });
          },
          child: Text('Open Second Page'),
        ),
      ),
    );
  }
}

这样,你就完成了在Flutter项目中使用union_annotation插件来定义和处理路由参数的过程。希望这能帮助你更好地理解和使用union_annotation插件。

回到顶部