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;
  }
}
相关推荐
LawrenceLan1 天前
Flutter 零基础入门(九):构造函数、命名构造函数与 this 关键字
开发语言·flutter·dart
一豆羹1 天前
macOS 环境下 ADB 无线调试连接失败、Protocol Fault 及端口占用的深度排查
flutter
行者961 天前
OpenHarmony上Flutter粒子效果组件的深度适配与实践
flutter·交互·harmonyos·鸿蒙
行者961 天前
Flutter与OpenHarmony深度集成:数据导出组件的实战优化与性能提升
flutter·harmonyos·鸿蒙
小雨下雨的雨1 天前
Flutter 框架跨平台鸿蒙开发 —— Row & Column 布局之轴线控制艺术
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨1 天前
Flutter 框架跨平台鸿蒙开发 —— Center 控件之完美居中之道
flutter·ui·华为·harmonyos·鸿蒙
小雨下雨的雨1 天前
Flutter 框架跨平台鸿蒙开发 —— Icon 控件之图标交互美学
flutter·华为·交互·harmonyos·鸿蒙系统
小雨下雨的雨1 天前
Flutter 框架跨平台鸿蒙开发 —— Placeholder 控件之布局雏形美学
flutter·ui·华为·harmonyos·鸿蒙系统
行者961 天前
OpenHarmony Flutter弹出菜单组件深度实践:从基础到高级的完整指南
flutter·harmonyos·鸿蒙
前端不太难1 天前
Flutter / RN / iOS,在长期维护下的性能差异本质
flutter·ios