在 flutter 中使用枚举的技巧

在 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 秒钟,对我来说是一个激励,感谢。

祝你有一个美好的一天~


© 猫哥

本文由mdnice多平台发布

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容