在 flutter 中使用枚举的技巧
前言
例如,不管是谁在 Kotlin 之后,再开发 Dart 都对它带来的种种限制感到失望。
其中之一是枚举类。单独使用枚举值是可以的,但是还有别的吗?你不得不用枚举,对吧?
这篇文章将会推荐几个 enum 枚举的使用技巧。
正文
旧的方式, 通过 extension 扩展枚举值
让我们提醒自己,这样的代码可能是什么样子的。下面是一组 ActivityType 。在某些时候,我们希望为每个活动分配一个数字和一个字符串值。也许我们的后端返回一个数字,但是我们当然不想在我们的应用程序代码中使用奇怪的数字来标记。相反,我们决定使用枚举。
enum ActivityType {
running,
climbing,
hiking,
cycling,
ski
}
extension ActivityTypeNumber on ActivityType {
int get number {
switch (this) {
case ActivityType.running:
return 1;
case ActivityType.climbing:
return 2;
case ActivityType.hiking:
return 5;
case ActivityType.cycling:
return 7;
case ActivityType.ski:
return 10;
}
}
}
extension ActivityTypeValue on ActivityType {
String get value {
switch (this) {
case ActivityType.running:
return 'Running';
case ActivityType.climbing:
return 'Climbing';
case ActivityType.hiking:
return 'Hiking';
case ActivityType.cycling:
return 'Cycling';
case ActivityType.ski:
return 'Skiing';
}
}
}
为了访问数字或 String 值:
final climbingInt = ActivityType.climbing.number;
final climbingString = ActivityType.climbing.value;
现在使用新的枚举值方式
幸运的是,随着 2022 年 5 月在 Google I/O 上发布 Flutter 3.0,我们不必再依赖这些令人长长的代码了。让我们使用新的和增强的枚举类重写代码。
https://medium.flutterdevs.com/flutter-3-0-whats-new-in-flutter-12259bf090ba
enum ActivityType {
running(1, 'Running'),
climbing(2, 'Climbing'),
hiking(5, 'Hiking'),
cycling(7, 'Cycling'),
ski(10, 'Skiing');
const ActivityType(this.number, this.value);
final int number;
final String value;
}
其实就是赋予了一些类的特性
所以这次很聪明! 访问值或数值保持不变。
在工作中,我们通常希望获得一个枚举或一个基于数字的值,这些数字是从后端接收的。
或者,基于活动的字符串名称(比如,如果我们得到“攀登”并想将其映射到 ActivityType.)。这一切都很容易做到:
enum ActivityType {
running(1, 'Running'),
climbing(2, 'Climbing'),
hiking(5, 'Hiking'),
cycling(7, 'Cycling'),
ski(10, 'Skiing');
const ActivityType(this.number, this.value);
final int number;
final String value; static ActivityType getTypeByTitle(String title) =>
ActivityType.values.firstWhere((activity) => activity.name == title);
static ActivityType getType(int number) => ActivityType.values.firstWhere((activity) => activity.number == number);
static String getValue(int number) => ActivityType.values.firstWhere((activity) => activity.number == number).value;
}
Name 是每个 enum 的默认属性,并返回一个该 enum 值的字符串,例如, activitytype.ski.name 是“ ski”。
final activityType = ActivityType.getTypeByTitle('hiking');
Console:
I/flutter ( 2896): activity: ActivityType.hiking
unknown 异常处理
请记住,如果由于某种原因所提供的标题或数字不在您的活动标题/数字中,您将得到一个糟糕的状态异常。这个案子有用:
正常访问
final activityType = ActivityType.getType(7);
final activityValue = ActivityType.getValue(7);
print('activity: $activityType - $activityValue');
Console:
I/flutter (24956): activity: ActivityType.cycling - Cycling
但这个不是:
final activityType = ActivityType.getType(77);
Console:
======== Exception caught by widgets library =======================================================
The following StateError was thrown building ActivityListScreen(dirty, state: _ConsumerState#c9a6a):
Bad state: No element
....
这是因为我们没有提供或 Else ()子句。函数。为了不出现错误,我们可以默认为未知类型:
enum ActivityType {
running(1, 'Running'),
climbing(2, 'Climbing'),
hiking(5, 'Hiking'),
cycling(7, 'Cycling'),
ski(10, 'Skiing'),
unknown(-1, '');
const ActivityType(this.number, this.value);
final int number;
final String value;static ActivityType getTypeByTitle(String title) =>
ActivityType.values.firstWhere((activity) => activity.name == title, orElse: () => ActivityType.unknown);
static ActivityType getType(int number) =>
ActivityType.values.firstWhere((activity) => activity.number == number, orElse: () => ActivityType.unknown);
static String getValue(int number) =>
ActivityType.values.firstWhere((activity) => activity.number == number, orElse: () => ActivityType.unknown).value;
}
extension 扩展处理枚举
或者只是不添加未知类型,而是返回一个可为空的值。这需要我们向列表中添加一个扩展函数。我发现它在应用程序的其他部分也很有用,不仅仅是枚举:
extension ListExtension<T> on List<T> {
T? firstWhereOrNull(bool Function(T element) condition) {
for (final element in this) {
if (condition(element)) return element;
}
return null;
}
}
然后我们的 ActivityType 看起来像这样:
enum ActivityType {
running(1, 'Running'),
climbing(2, 'Climbing'),
hiking(5, 'Hiking'),
cycling(7, 'Cycling'),
ski(10, 'Skiing');
const ActivityType(this.number, this.value);
final int number;
final String value; static ActivityType? getTypeByTitle(String title) =>
ActivityType.values.firstWhereOrNull((activity) => activity.name == title);
static ActivityType? getType(int number) =>
ActivityType.values.firstWhereOrNull((activity) => activity.number == number);
static String? getValue(int number) =>
ActivityType.values.firstWhereOrNull((activity) => activity.number == number)?.value;
}
对于一些奇怪的输入数据,我们得到的是空值,而不是异常和红色屏幕。
final activity = ActivityType.getTypeByTitle('abc');
final activityType = ActivityType.getType(77);
final activityValue = ActivityType.getValue(99);
print('$activity - $activityType - $activityValue');
Console:
I/flutter ( 2896): null - null - null
activityString()
加入自定义函数 如 根据您的需要、后端返回的内容等,选择两种方法中的一种。
还有一件事,当然可以使用非静态函数,比如下面的 activityString() :
enum ActivityType {
running(1, 'Running'),
climbing(2, 'Climbing'),
hiking(5, 'Hiking'),
cycling(7, 'Cycling'),
ski(10, 'Skiing');
const ActivityType(this.number, this.value);
final int number;
final String value; static ActivityType? getTypeByTitle(String title) =>
ActivityType.values.firstWhereOrNull((activity) => activity.name == title);
static ActivityType? getType(int number) =>
ActivityType.values.firstWhereOrNull((activity) => activity.number == number);
static String? getValue(int number) =>
ActivityType.values.firstWhereOrNull((activity) => activity.number == number)?.value;
String activityString(String userName) => '$userName is $value';
}
然后,对某个枚举调用它,得到一个漂亮的字符串,您可以立即在 UI 中使用该字符串:
final userIsWorkingOut = ActivityType.climbing.activityString('Emily Jules');
print('$userIsWorkingOut');
Console:
I/flutter (28053): Emily Jules is Climbing
就是这样! 享受在 Flutter 中使用一个增强的枚举 😉
结束语
如果本文对你有帮助,请转发让更多的朋友阅读。
也许这个操作只要你 3 秒钟,对我来说是一个激励,感谢。
祝你有一个美好的一天~
© 猫哥
微信 ducafecat
https://wiki.ducafecat.tech
https://ducafecat.com