Flutter实用工具Indexer列表索引和Search搜索帮助。

1.列表索引

效果图:

indexer.dart

Dart 复制代码
import 'package:json_annotation/json_annotation.dart';

abstract class Indexer {
  ///用于排序的字母
  @JsonKey(includeFromJson: false, includeToJson: false)
  String? sortLetter;

  ///用于排序的拼音
  @JsonKey(includeFromJson: false, includeToJson: false)
  String? fullLetter;

  ///用于继承类设置需要索引的字段
  String? getFullName();
}

indexer_util.dart

Dart 复制代码
import 'package:kq_flutter_widgets/utils/ex/string_ex.dart';
import 'package:lpinyin/lpinyin.dart';

import 'indexer.dart';

class IndexerUtil {
  ///始终排在列表最顶端,可自己改为特定值
  static String ALWAYS_TOP_SYMBOL = "★";

  ///始终排在列表最底部,可自己改为特定值
  static String ALWAYS_BOTTOM_SYMBOL = "#";

  ///给数据排序,默认根据{@link IndexModel#getSortLetter()}内容升序排列,其中有两个特殊字符{@link #ALWAYS_TOP_SYMBOL}
  ///和{@link #ALWAYS_BOTTOM_SYMBOL}。如果{@link IndexModel#getSortLetter()}获取内容为{@link #ALWAYS_TOP_SYMBOL},
  ///则始终排在最顶端,如果{@link IndexModel#getSortLetter()}获取内容为{@link #ALWAYS_BOTTOM_SYMBOL},则始终排在最低端。
  ///通常情况下都无需调用{@link IndexModel#setSortLetter(String)},除非你想干预某个数据在列表的排序结果

  /// @param isIndexNumber 是否索引数字,如果不索引,则全部放到{@linkplain #ALWAYS_BOTTOM_SYMBOL #}号分组
  ///                      {@code true} 索引
  ///                     {@code false} 不索引
  /// @param isUserName    是否是人名,{@code true} 处理多音字作为姓氏时的正确读音
  static List<String> getIndexData<T extends Indexer>(
      {required List<T> data,
      LatterType type = LatterType.lowerCase,
      bool isIndexNumber = false}) {
    for (T t in data) {
      _swap(t, isIndexNumber, type);
    }
    _sortData(data);

    ///TODO 优化,从sectionData直接过去key
    List<String> indexData = [];
    for (T t in data) {
      if (t.sortLetter == null && !indexData.contains(ALWAYS_BOTTOM_SYMBOL)) {
        indexData.add(ALWAYS_BOTTOM_SYMBOL);
      } else if (!indexData.contains(t.sortLetter)) {
        indexData.add(t.sortLetter!);
      }
    }
    return indexData;
  }

  ///给数据排序,默认根据{@link IndexModel#getSortLetter()}内容升序排列,其中有两个特殊字符{@link #ALWAYS_TOP_SYMBOL}
  ///和{@link #ALWAYS_BOTTOM_SYMBOL}。如果{@link IndexModel#getSortLetter()}获取内容为{@link #ALWAYS_TOP_SYMBOL},
  ///则始终排在最顶端,如果{@link IndexModel#getSortLetter()}获取内容为{@link #ALWAYS_BOTTOM_SYMBOL},则始终排在最低端。
  ///通常情况下都无需调用{@link IndexModel#setSortLetter(String)},除非你想干预某个数据在列表的排序结果

  /// @param isIndexNumber 是否索引数字,如果不索引,则全部放到{@linkplain #ALWAYS_BOTTOM_SYMBOL #}号分组
  ///                      {@code true} 索引
  ///                     {@code false} 不索引
  /// @param isUserName    是否是人名,{@code true} 处理多音字作为姓氏时的正确读音
  static Map<String, List<T>> getSectionData<T extends Indexer>(
      {required List<T> data,
      LatterType type = LatterType.lowerCase,
      bool isIndexNumber = false}) {
    for (T t in data) {
      _swap(t, isIndexNumber, type);
    }
    _sortData(data);

    Map<String, List<T>> sectionData = {};
    List<String>? indexData = [];
    for (T t in data) {
      if (t.sortLetter == null && !indexData.contains(ALWAYS_BOTTOM_SYMBOL)) {
        indexData.add(ALWAYS_BOTTOM_SYMBOL);
        sectionData.putIfAbsent(ALWAYS_BOTTOM_SYMBOL, () => [t]);
      } else if (!indexData.contains(t.sortLetter)) {
        indexData.add(t.sortLetter!);
        sectionData.putIfAbsent(t.sortLetter!, () => [t]);
      } else {
        sectionData.update(t.sortLetter!, (value) {
          value.add(t);
          return value;
        });
      }
    }
    return sectionData;
  }

  ///排序
  static _sortData<T extends Indexer>(List<T> data) {
    data.sort((left, right) {
      if (left.sortLetter == ALWAYS_TOP_SYMBOL) {
        return -1;
      } else if (left.sortLetter != ALWAYS_TOP_SYMBOL &&
          right.sortLetter == ALWAYS_TOP_SYMBOL) {
        return 1;
      } else if (left.sortLetter == ALWAYS_BOTTOM_SYMBOL &&
          right.sortLetter != ALWAYS_BOTTOM_SYMBOL) {
        return 1;
      } else if (right.sortLetter == ALWAYS_BOTTOM_SYMBOL) {
        return -1;
      } else {
        return (left.sortLetter ?? "").compareTo(right.sortLetter ?? "");
      }
    });
  }

  ///获取汉字全拼首字母
  static String? _getSelling<T extends Indexer>(T t) {
    String? latter = t.getFullName();
    if (latter.isNullOrEmpty) {
      return null;
    }
    return PinyinHelper.getFirstWordPinyin(latter!);
  }

  ///根据全拼获取首字母
  static String _getFirstLetter(
      String pinyin, bool isIndexNumber, LatterType type) {
    if (pinyin.isNullOrEmpty) {
      return ALWAYS_BOTTOM_SYMBOL;
    }
    String sortString = pinyin.substring(0, 1);
    if (RegExp(r"[A-Za-z]").hasMatch(sortString)) {
      return type == LatterType.upperCase
          ? sortString.toUpperCase()
          : sortString.toLowerCase();
    } else if (isIndexNumber && RegExp(r"\d").hasMatch(sortString)) {
      return sortString;
    } else {
      return ALWAYS_BOTTOM_SYMBOL;
    }
  }

  ///数据转化
  static _swap<T extends Indexer>(T t, bool isIndexNumber, LatterType type) {
    t.fullLetter ??= _getSelling(t);
    t.sortLetter ??= _getFirstLetter(t.fullLetter!, isIndexNumber, type);
    if (t.sortLetter != null && t.sortLetter!.isEmpty) {
      t.sortLetter = ALWAYS_BOTTOM_SYMBOL;
    }
  }
}

enum LatterType {
  ///大写
  upperCase,

  ///小写
  lowerCase
}

上面的只是帮助类,帮助数据分组和索引,界面的分组和展示需要自己布局实现。

2.搜索帮助

search_able.dart

Dart 复制代码
abstract class SearchAble{
  String toSearch();
}

search_util.dart

Dart 复制代码
import 'package:kq_flutter_widgets/utils/ex/string_ex.dart';
import 'package:kq_flutter_widgets/utils/search/search_able.dart';

/// 搜索帮助类
class SearchUtil {
  /// 根据搜索内容搜索出相关数据
  /// 用户需要搜索的数据类需要继承[SearchAble],并实现[toSearch]方法
  static List<T> search<T extends SearchAble>(String? searchText, List<T> data) {
    List<T> searchData = [];
    if (searchText.isNotNullOrEmpty) {
      for (T t in data) {
        if (t.toSearch().isNotNullOrEmpty &&
            t.toSearch().toLowerCase().trim().contains(searchText!.toLowerCase())) {
          searchData.add(t);
        }
      }
    }
    return searchData;
  }
}
相关推荐
火柴就是我20 小时前
flutter 之真手势冲突处理
android·flutter
Speed12321 小时前
`mockito` 的核心“打桩”规则
flutter·dart
法的空间21 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
恋猫de小郭21 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
玲珑Felone1 天前
从flutter源码看其渲染机制
android·flutter
ALLIN2 天前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei2 天前
Flutter 国际化
flutter
Dabei2 天前
Flutter MQTT 通信文档
flutter
Dabei2 天前
Flutter 中实现 TCP 通信
flutter
孤鸿玉2 天前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter