在 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

Last Updated:
Contributors: ducafecat