Flutter 插件turn_gen的使用
Flutter 插件turn_gen的使用
欢迎来到 TurnGen
!这个项目是一组脚本组合而成的命令行工具。所有脚本都是用Dart语言编写的,并且可以即时运行而无需使用 build_runner
。这些脚本旨在简化各种任务,例如:
- 操作枚举类
- 在数据类中创建不同的方法
- 生成资源文件夹中所有文件的链接
- 从标准构造函数创建联合类型
安装
要使用 TurnGen
,只需将其添加到 pubspec.yaml
文件作为 dev_dependencies
:
对于Flutter项目:
flutter pub add --dev turn_gen
对于Dart项目:
dart pub add --dev turn_gen
如果您打算使用资源文件夹中的链接生成器,可以在 pubspec.yaml
中添加输出文件路径,默认情况下,文件将在 lib/gen/
中生成:
turn_gen:
assets_output: "lib/app_gen/"
如果在 pubspec.yaml
中将 show_comments
设置为 true
,这意味着方法和变量上的注释将在您的代码中显示,这极大地提高了可读性并帮助您理解发生了什么。默认情况下,此设置被禁用。
turn_gen:
show_comments: true
然后运行 flutter pub get
或 dart pub get
来安装包。
使用
自动检测正在运行的脚本
TurnGen
可以通过单个命令来运行,该命令会搜索具有特定注释的文件:
// turngen
我们使用以下命令启动它:
dart run turn_gen
例如,当使用 union
脚本时:
import 'package:meta/meta.dart';
// turngen
/* no: tojson fromJson */
@immutable
class _ConnectivityState {
const _ConnectivityState.isDisonnected();
const _ConnectivityState.isConnected();
const _ConnectivityState.notDetermined();
}
// end
例如,当使用 data
脚本时:
// import 'package:meta/meta.dart';
// turngen
@immutable
class DataFio {
/* init:'' */
final String surname;
/* init:'' */
final String name;
/* init:'' */
final String patronymic;
// end
}
例如,当使用 enum
脚本时:
// turngen
enum EnumLang {
ru,
en;
// end
}
或者:
// turngen
enum EnumActivity {
normal(10),
light(5),
none(0);
const EnumActivity(this.value);
final int value;
// end
}
但是,运行此命令比直接调用所需的脚本稍慢一些,这些脚本将在下面描述。
枚举脚本
上述图显示了 enum
类的一些使用方式。Turngen
为方便操作 enum
添加了一些额外的方法。最重要的是,在构造函数中变量的类型并不重要。关键是要在关闭大括号之前添加注释 // end
以了解生成开始的位置。
以下是运行脚本的命令:
dart run turn_gen -t enum -f <path to your file>
如果您使用的是 VSCode
,可以在 tasks.json
中添加任务:
{
"label": "turn_gen enum",
"type": "dart",
"command": "dart",
"args": ["run", "turn_gen", "-t", "enum", "-f", "${file}"],
}
运行脚本后,您将获得额外的方法并覆盖标准方法:
from...
from...OrNull
map
maybeMap
maybeMapOrNull
mapValue
maybeMapValue
maybeMapOrNullValue
getListValues
compareTo
toString
示例
enum Speed implements Comparable<Speed> {
stop(0),
slow(5),
normal(10),
fast(20);
const Speed(this.value);
final int value;
// end
// --TURN_GEN--
// (enum)
// *************************************
// GENERATED CODE
// *************************************
static Speed fromValue(
int? value, {
Speed? fallback,
}) {
switch (value) {
case 0:
return stop;
case 5:
return slow;
case 10:
return normal;
case 20:
return fast;
default:
return fallback ??
(throw ArgumentError.value(
value,
'value',
'Value not found in Speed',
));
}
}
static Speed? fromValueOrNull(
int? value,
) {
switch (value) {
case 0:
return stop;
case 5:
return slow;
case 10:
return normal;
case 20:
return fast;
default:
return null;
}
}
T map<T>({
required T Function() stop,
required T Function() slow,
required T Function() normal,
required T Function() fast,
}) {
switch (this) {
case Speed.stop:
return stop();
case Speed.slow:
return slow();
case Speed.normal:
return normal();
case Speed.fast:
return fast();
}
}
T mapValue<T>({
required T stop,
required T slow,
required T normal,
required T fast,
}) {
switch (this) {
case Speed.stop:
return stop;
case Speed.slow:
return slow;
case Speed.normal:
return normal;
case Speed.fast:
return fast;
}
}
T maybeMap<T>({
required T Function() orElse,
T Function()? stop,
T Function()? slow,
T Function()? normal,
T Function()? fast,
}) =>
map<T>(
stop: stop ?? orElse,
slow: slow ?? orElse,
normal: normal ?? orElse,
fast: fast ?? orElse,
);
T maybeMapValue<T>({
required T orElse,
T? stop,
T? slow,
T? normal,
T? fast,
}) =>
mapValue<T>(
stop: stop ?? orElse,
slow: slow ?? orElse,
normal: normal ?? orElse,
fast: fast ?? orElse,
);
T? maybeMapOrNull<T>({
T Function()? stop,
T Function()? slow,
T Function()? normal,
T Function()? fast,
}) =>
maybeMap<T?>(
orElse: () => null,
stop: stop,
slow: slow,
normal: normal,
fast: fast,
);
T? maybeMapOrNullValue<T>({
T? stop,
T? slow,
T? normal,
T? fast,
}) =>
maybeMapValue<T?>(
orElse: null,
stop: stop,
slow: slow,
normal: normal,
fast: fast,
);
static List<int> getListValue() => Speed.values.map((e) => e.value).toList();
@override
int compareTo(Speed other) => index.compareTo(other.index);
}
extension $Speed on Speed {
bool get isStop => this == Speed.stop;
bool get isSlow => this == Speed.slow;
bool get isNormal => this == Speed.normal;
bool get isFast => this == Speed.fast;
}
资源脚本
TurnGen
还允许生成资源文件夹中所有文件的字符串常量,并且可以根据文件名使用不同的字符和字母。如果发现相同的文件名,则会在常量名称中添加数字。
如果您需要不同的路径来生成文件,请在 pubspec.yaml
中使用以下设置:
turn_gen:
assets_output: "lib/gen/"
要启动,请使用以下命令:
dart run turn_gen assets
如果您使用的是 VSCode
,可以在 tasks.json
中添加任务:
{
"label": "turn_gen assets",
"type": "shell",
"command": "dart run turn_gen assets",
"problemMatcher": []
}
运行脚本后,您将获得一个类中的所有文件路径:
示例资源生成器
class AssetPaths {
const AssetPaths._();
/// * 大小:8.8 KB
/// * 文件路径:_assets/icons/app_icons.ttf
static const String appIconsIcons = 'assets/icons/app_icons.ttf';
/// * 大小:24.6 KB
/// * 文件路径:_assets/image/onboarding_remind_you.svg
static const String onboardingRemindYouImage = 'assets/image/onboarding_remind_you.svg';
/// * 大小:60.8 KB
/// * 文件路径:_assets/image/splash.png
static const String splashImage = 'assets/image/splash.png';
/// * 大小:4.8 KB
/// * 文件路径:_assets/lottie/load_btn.json
static const String loadBtnLottie = 'assets/lottie/load_btn.json';
...
/// TTF 资产列表
static const List<String> valuesTTF = [appIconsIcons];
/// SVG 资产列表
static const List<String> valuesSVG = [onboardingRemindYouImage, icErrorSvg, icErrorCloseSvg, icInfoSvg, icInfoCloseSvg, icSuccessSvg, icSuccessCloseSvg, icWarningSvg, icWarningCloseSvg, logoSvg, onb1Svg, onb2Svg, onb3Svg, onb4Svg, sortAscSvg, sortDescSvg];
/// PNG 资产列表
static const List<String> valuesPNG = [splashImage];
/// JSON 资产列表
static const List<String> valuesJSON = [loadBtnLottie, loadPageLottie, waterDownLottie, waterUpLottie];
/// 所有资产列表
static const List<String> valuesAll = [appIconsIcons, onboardingRemindYouImage, splashImage, loadBtnLottie, loadPageLottie, waterDownLottie, waterUpLottie, icErrorSvg, icErrorCloseSvg, icInfoSvg, icInfoCloseSvg, icSuccessSvg, icSuccessCloseSvg, icWarningSvg, icWarningCloseSvg, logoSvg, onb1Svg, onb2Svg, onb3Svg, onb4Svg, sortAscSvg, sortDescSvg];
}
数据脚本
TurnGen
脚本可以为 Dart 类生成和覆盖额外的方法,例如:
toMap
/fromJson
和fromMap
/fromJson
/fromDynamicMap
用于 Map/Json 序列化和反序列化copyWith
- 用于克隆具有不同属性的对象operator ==
和重写hashCode
(因为TurnGet
仅适用于不可变类)toString
- 显示对象的所有属性列表
最重要的是,我们只需通过在类体中添加注释来进行定制,以下是必需的注释:
@immutable
class RegistrationState {
final bool isLoad;
final String? name;
final List<int> activitySelected;
// end
}
现在让我们描述使用 TurnGen
的基本条件:
- 类的所有字段都必须是
final
- 声明完所有字段后,在末尾添加注释
// end
就这样!
额外类设置
您可以在类的开头使用注释添加其他设置,例如:
- 只有
copyWith
方法。
/* only: copyWith */
class RegistrationState {
...
- 移除某些方法或几个方法。
/* no: fromMap toMap */
class RegistrationState {
...
- 使用
equatable
库。
/* use: equatable */
class RegistrationState {
...
在上面的示例中,您可以组合来自其他方法的不同选项。
额外变量设置
变量也有设置,我们只需在类上方写入我们的关键字,例如:
- 您可以初始化变量为任何文本。
/* init: true */
final bool isLoad;
/* init: 'Jon' */
final String name;
- 如果未定义变量的类型,
TurnGen
将尝试确定它并向您提示,但您可以明确指定它,关键字为type:
和可能的选项enum
data
List<data>
。
/*
type: enum
init: FormzSubmissionStatus.initial
*/
final FormzSubmissionStatus status;
/*
type: data
init: const DateRegModel()
*/
final DateRegModel dateRegModel;
/* type: List<data> */
final List<Name> nameList;
- 如果
TurnGen
无法确定变量类型,请覆盖toMap
或fromMap
方法。
/*
init: const DateRegModel()
fromMap: DateRegModel.fromMap(map['dateRegModel'] as Map<String, dynamic>)
toMap: dateRegModel.toMap()
*/
final DateRegModel dateRegModel;
使用
要启动,请使用以下命令:
dart run turn_gen
# 或者
dart run turn_gen -t data -f <path to your file>
如果您使用的是 VSCode
,可以在 tasks.json
中添加任务:
{
"label": "turn_gen data",
"type": "dart",
"command": "dart",
"args": ["run", "turn_gen", "-t", "data", "-f", "${file}"]
}
执行脚本后,您将获得一个带有新方法和覆盖方法的标准 Dart 类:
示例
import 'dart:convert';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
// turngen
@immutable
class RegistrationState {
final bool isLoad;
final String? name;
final List<int> activitySelected;
// end
// --TURN_GEN--
// (data)
// *************************************
// GENERATED CODE
// *************************************
const RegistrationState({
required this.isLoad,
required this.activitySelected,
this.name,
});
Map<String, dynamic> toMap() {
return <String, dynamic>{
'isLoad': isLoad,
'name': name,
'activitySelected': activitySelected,
};
}
factory RegistrationState.fromMap(Map<dynamic, dynamic> map) {
return RegistrationState(
isLoad: map['isLoad'] != null
? map['isLoad'] as bool
: throw Exception(
"map['isLoad']_type_'Null'",
),
name: map['name'] as String?,
activitySelected: map['activitySelected'] != null
? (map['activitySelected'] as List<dynamic>)
.map((e) => e as int)
.toList()
: throw Exception(
"map['activitySelected']_type_'Null'",
),
);
}
RegistrationState copyWith({
bool? isLoad,
String? name,
List<int>? activitySelected,
}) {
return RegistrationState(
isLoad: isLoad ?? this.isLoad,
name: name ?? this.name,
activitySelected: activitySelected ?? this.activitySelected,
);
}
String toJson() => json.encode(toMap());
factory RegistrationState.fromJson(String source) =>
RegistrationState.fromMap(
json.decode(source) as Map<String, dynamic>,
);
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is RegistrationState &&
(identical(
other.isLoad,
isLoad,
) ||
other.isLoad == isLoad) &&
(identical(
other.name,
name,
) ||
other.name == name) &&
const DeepCollectionEquality().equals(
other.activitySelected,
activitySelected,
));
}
@override
int get hashCode => Object.hashAll([
runtimeType,
isLoad,
name,
const DeepCollectionEquality().hash(
activitySelected,
),
]);
@override
String toString() {
return 'RegistrationState(isLoad: $isLoad, name: $name, activitySelected: $activitySelected, )';
}
}
联合脚本
TurnGen
脚本可以生成“联合类型”通过创建具有命名构造函数的类,但这需要创建一个假的私有类。这个类在任何地方都没有使用,但对于修改生成的代码很有用。并且在类末尾添加 // end
注释,如下所示的示例:
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
// turngen
class _Union {
_Union.success({required List<User> listUser});
_Union.load();
_Union.init([String hello = 'Hello world']);
_Union.error({String msg = ''});
}
// end
使用
要启动,请使用以下命令:
dart run turn_gen
# 或者
dart run turn_gen -t union -f <path to your file>
如果您使用的是 VSCode
,可以在 tasks.json
中添加任务:
{
"label": "turn_gen union",
"type": "dart",
"command": "dart",
"args": ["run", "turn_gen", "-t", "union", "-f", "${file}"]
}
运行脚本后,您将获得额外的方法并覆盖标准方法:
map
maybeMap
mapOrNull
when
compareTo
toString
,operator ==
,hashCode
toJson/fromJson
添加了将 Union
类转换为 JSON 字符串和反向的功能。在进行初始转换时,您需要提供 tag
。然而,对于后续转换,tag
参数是可选的。
// union class example
// turngen
@immutable
class _ApiLoanSchedule {
/// 创建成功的 API 贷款计划。
const _ApiLoanSchedule.success({
List<ApiLoanScheduleItem> list = const [],
});
/// 创建错误的 API 贷款计划。
const _ApiLoanSchedule.error({
String message = '',
String error = '',
String code = '',
});
}
// ... 其他代码
// 反序列化类
return response.statusCode == 200
? ApiLoanSchedule.fromJson(
response.data,
ApiLoanScheduleTag.success,
)
: ApiLoanSchedule.fromJson(
response.data,
ApiLoanScheduleTag.error,
);
// 如何使用
loanScheduleModel.map(
success: (v) {
// Something to do
},
error: (v) {
// Something to do
},
);
// 数据序列化
final loanScheduleJson = loanScheduleModel.toJson();
生成文件示例
class _Union {
_Union.success({required List<User> listUser});
_Union.load();
_Union.init([String hello = 'Hello world']);
_Union.error({String msg = ''});
}
// end
// --TURN_GEN--
// *************************************
// GENERATED CODE
// *************************************
@immutable
class Union {
const Union.success({required List<User> listUser}):
_tag = _UnionTag.success,
_listUser_success = listUser,
_hello_init = null,
_msg_error = null;
const Union.load():
_tag = _UnionTag.load,
_listUser_success = null,
_hello_init = null,
_msg_error = null;
const Union.init([String hello = 'Hello world']):
_tag = _UnionTag.init,
_listUser_success = null,
_hello_init = hello,
_msg_error = null;
const Union.error({String msg = ''}):
_tag = _UnionTag.error,
_listUser_success = null,
_hello_init = null,
_msg_error = msg;
T? mapOrNull<T>({
T? Function(_UnionSuccess v)? success,
T? Function(_UnionLoad v)? load,
T? Function(_UnionInit v)? init,
T? Function(_UnionError v)? error,
}) {
switch (_tag) {
case _UnionTag.success:
return success?.call(_UnionSuccess(_listUser_success!));
case _UnionTag.load:
return load?.call(const _UnionLoad());
case _UnionTag.init:
return init?.call(_UnionInit(_hello_init!));
case _UnionTag.error:
return error?.call(_UnionError(_msg_error!));
}
}
T map<T>({
required T Function(_UnionSuccess v) success,
required T Function(_UnionLoad v) load,
required T Function(_UnionInit v) init,
required T Function(_UnionError v) error,
}) {
switch (_tag) {
case _UnionTag.success:
return success(_UnionSuccess(_listUser_success!));
case _UnionTag.load:
return load(const _UnionLoad());
case _UnionTag.init:
return init(_UnionInit(_hello_init!));
case _UnionTag.error:
return error(_UnionError(_msg_error!));
}
}
T maybeMap<T>({
T Function(_UnionSuccess v)? success,
T Function(_UnionLoad v)? load,
T Function(_UnionInit v)? init,
T Function(_UnionError v)? error,
required T Function() orElse,
}) {
switch (_tag) {
case _UnionTag.success:
if(success != null) return success(_UnionSuccess(_listUser_success!));
return orElse();
case _UnionTag.load:
if(load != null) return load(const _UnionLoad());
return orElse();
case _UnionTag.init:
if(init != null) return init(_UnionInit(_hello_init!));
return orElse();
case _UnionTag.error:
if(error != null) return error(_UnionError(_msg_error!));
return orElse();
}
}
T when<T>({
required T Function (List<User> listUser) success,
required T Function () load,
required T Function (String hello) init,
required T Function (String msg) error,
}) {
switch (_tag) {
case _UnionTag.success:
return success(_listUser_success!);
case _UnionTag.load:
return load();
case _UnionTag.init:
return init(_hello_init!);
case _UnionTag.error:
return error(_msg_error!);
}
}
@override
bool operator ==(dynamic other) {
switch (_tag) {
case _UnionTag.success:
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Union &&
const DeepCollectionEquality().equals(other._listUser_success, _listUser_success,));
case _UnionTag.load:
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Union );
case _UnionTag.init:
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Union &&
(identical(other._hello_init, _hello_init) || other._hello_init == _hello_init));
case _UnionTag.error:
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is Union &&
(identical(other._msg_error, _msg_error) || other._msg_error == _msg_error));
}
}
@override
int get hashCode {
switch (_tag) {
case _UnionTag.success:
return Object.hashAll([runtimeType, const DeepCollectionEquality().hash(_listUser_success)]);
case _UnionTag.load:
return Object.hashAll([runtimeType]);
case _UnionTag.init:
return Object.hashAll([runtimeType, _hello_init]);
case _UnionTag.error:
return Object.hashAll([runtimeType, _msg_error]);
}
}
@override
String toString() {
switch (_tag) {
case _UnionTag.success:
return 'Union.success(listUser: $_listUser_success)';
case _UnionTag.load:
return 'Union.load()';
case _UnionTag.init:
return 'Union.init(hello: $_hello_init)';
case _UnionTag.error:
return 'Union.error(msg: $_msg_error)';
}
}
final _UnionTag _tag;
final List<User>? _listUser_success;
final String? _hello_init;
final String? _msg_error;
}
enum _UnionTag {
success,
load,
init,
error,
}
@immutable
class _UnionSuccess extends Union {
const _UnionSuccess(this.listUser) : super.success(listUser: listUser);
final List<User> listUser;
}
@immutable
class _UnionLoad extends Union {
const _UnionLoad() : super.load();
}
@immutable
class _UnionInit extends Union {
const _UnionInit(this.hello) : super.init( hello);
final String hello;
}
@immutable
class _UnionError extends Union {
const _UnionError(this.msg) : super.error(msg: msg);
final String msg;
}
更新所有文件
如果需要更新所有使用 TurnGen
的文件,这些文件包含以下文本:
// --TURN_GEN--
// (data)
// *************************************
// GENERATED CODE
// *************************************
只需运行以下命令:
dart run turn_gen build
更多关于Flutter 插件turn_gen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter 插件turn_gen的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,如果你遇到一个名为 turn_gen
的插件,并且它的功能描述为“undefined”(未定义),这意味着我们没有官方文档或明确的功能说明来指导使用。然而,作为一个IT专家,我可以提供一些通用的方法来探索和使用这个插件,包括如何安装、初始化以及尝试调用其可能的方法。
请注意,由于我们不知道 turn_gen
插件的具体功能,以下代码案例将基于Flutter插件的一般使用模式进行假设。
1. 安装插件
首先,你需要在 pubspec.yaml
文件中添加这个插件的依赖。由于我们不知道具体的依赖名称和版本,这里假设依赖名称为 turn_gen
(在实际使用中,你需要根据插件的实际名称进行修改):
dependencies:
flutter:
sdk: flutter
turn_gen: ^x.y.z # 替换为实际的版本号
然后运行 flutter pub get
来安装插件。
2. 导入插件
在你的 Dart 文件中导入插件:
import 'package:turn_gen/turn_gen.dart';
3. 初始化插件(如果需要)
有些插件可能需要在应用启动时进行初始化。由于我们不知道 turn_gen
插件是否需要初始化,这里提供一个假设性的初始化代码示例:
void main() {
WidgetsFlutterBinding.ensureInitialized();
// 假设turn_gen有一个初始化方法initTurnGen
// TurnGen.instance.initTurnGen();
runApp(MyApp());
}
请注意,上面的 initTurnGen
方法是假设存在的,你需要根据插件的实际API进行调整。
4. 使用插件功能
由于我们不知道 turn_gen
插件的具体功能,这里只能提供一些通用的调用方法示例。假设插件有一个名为 generateSomething
的方法,你可以这样调用它:
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String result = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TurnGen Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Result: $result',
),
ElevatedButton(
onPressed: () async {
// 假设turn_gen有一个名为generateSomething的异步方法
// String generated = await TurnGen.instance.generateSomething();
// setState(() {
// result = generated;
// });
},
child: Text('Generate Something'),
),
],
),
),
);
}
}
同样,上面的 generateSomething
方法和 TurnGen.instance
是假设存在的。你需要根据插件的实际API文档进行调整。
结论
由于 turn_gen
插件的功能是未知的,上述代码案例都是基于假设的。在实际使用中,你需要查阅插件的官方文档或源代码来了解其具体的API和使用方法。如果插件没有提供足够的文档,你可以尝试在GitHub的issue页面或相关社区寻求帮助。