パッケージ、リポジトリ、アプリカテゴリを検索

パッケージ詳細v5.0.0

diffutil_dart

2つのリスト間の差分を、編集操作のリストとして計算します。たとえば、StatefulWidgetを維持しなくてもFlutterのリストを暗黙的にアニメーション化する場合に使用されます。

AndroidiOSWebmacOSWindowsLinux
30日間ダウンロード
21.9万
いいね数
104
Pub ポイント
160

パッケージをインストール

flutter pub add diffutil_dart

パッケージ概要

公開情報に基づく選定ガイドです。参考としてご利用ください。

diffutil_dart は2つのリスト間の差分を計算し、1つのリストを別のリストに変換するための編集操作(挿入、削除、移動)のシーケンスを生成します。これにより、Flutterのリストで状態を手動で管理せずに効率的かつ暗黙的なアニメーションを実現できます。特に動的なデータを取り扱う場合、最小限の再構築でUIを更新できるため、パフォーマンスと応答性が向上します。このパッケージは軽量であり、Flutterがサポートするすべての主要プラットフォームで互換性があります。

用途

  • Flutter でのリスト更新のアニメーション
  • リストの変更を効率的に同期する
  • 不要なウィジェット再構築の削減
  • スムーズなスクロール遷移の実装
  • 動的データソースの更新
  • リストの状態管理を簡素化する

主な機能

  • 正確な編集操作を生成します
  • 挿入、削除、移動操作をサポートします
  • パフォーマンス向上のための最小限の再ビルド
  • クロスプラットフォーム互換性
  • 軽量で統合が簡単
  • 手動での状態管理は不要です

適している対象

  • 動的なリストを使用するFlutterの開発者
  • スムーズなUIアニメーションを重視するチーム
  • 頻繁にリストが更新されるアプリ
  • リスト処理におけるボイラープレートを減らしたい人
  • 高性能リストレンダリングを目指すプロジェクト

注意事項

  • 編集操作ロジックの理解が必要です
  • シンプルなリスト構造に最適
  • 複雑なネストされたデータを最適化しない可能性があります
  • リスト以外のデータ型には適していない
  • リスト同士の差分比較に限定
  • デフォルトでは深さの等価性を処理しない

元の README

関連するソースリポジトリの README 原文のスナップショットです。最新の内容はリポジトリをご覧ください。

diffutil.dart

Pub Package Build Status codecov

Calculate the difference between two lists.

Heavily inspired bei Android's DiffUtil class, the code was adopted for Dart.

Uses Myers algorithm internally. For an explanation of how the algorithm works internally, for details I recommend this great series of articles: https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/

What is this good for?

There are often situations, where an app displays a list of items, which are fetched from an external data source like a server endpoint or a database, and updates are not sent as delta, but as a whole new list.

It can be useful to take the old list and the new list and calculate the difference between those two, for example when animating the insertion and removal of new items in the displayed list (See diffutil_sliverlist).

This package does exactly that: It takes two lists and calculates the difference (or to be more accurate: edit script) between those two lists as list of Insert, Remove, Change (only when using custom delegates) and Move (when enabled) operations.

Usage

Calculating diffs:

Simple usage:

final diffResult = calculateListDiff<int>([1, 2 ,3], [1, 3, 4]);

Custom equality:

final diffResult = calculateListDiff<YourClassWithId>(oldList, newList, (o1, o2) => o1.id == o2.id);

If you don't want to use plain old Dart lists (for example if you're using built_value or kt.dart), and don't want to convert your custom list to standard lists, you can use the calculateDiff function and implement your own DiffDelegate easily.

Or use calculateCustomListDiff and CustomListDiffDelegate.

Move detection is disabled by default.

Using the result:

Call .getUpdates() on the diffResult to get a List of DiffUpdate objects. These are sealed classes of type Insert, Remove, Change or Move. Move operations are only calculated if calculateListDiff was called with detectMoves: true

The order of these operations matters! They describe how to turn the previous list into the new list, when applied in the order as they are returned.

  for (final update in diffResult.getUpdates())
    update.when(
      insert: (pos, count) => print("inserted $count on $pos"),
      remove: (pos, count) => print("removed $count on $pos"),
      change: (pos, payload) => print("changed on $pos with payload $payload"),
      move: (from, to) => print("move $from to $to"),
    );

By default, Insert and Remove Operations are batched. (e.g. multiple consecutive inserts or removes are represented by a single Insert/Remove object with a count field > 1). If you want to turn off edit script batching, call getUpdates(batch: false). This means, every Insert and Remove operation will have a count of 1 and the edit script of [] and [1, 2] will be

[Insert(position: 0, count : 1), Insert(position: 0, count :1 )]

instead of

[Insert(position: 0, count: 2)]

Updates with data

If you need the concrete items that have been inserted/removed/changed/moved, call getUpdatesWithData().


     diffutil.calculateListDiff([1, 2, 3], [1, 0, 3]).getUpdatesWithData();

returns

      [
        DataRemove(position: 1, data: 2),
        DataInsert(position: 1, data: 0)
      ];

The result of getUpdatesWithData() cannot be batched. You can use the resulting Iterable<DataDiffUpdate> like this:

 for (final update in updates) {
      update.when(
        insert: (pos, data) => print('insert $pos $data'),
        remove: (pos, data) => print('remove $pos $data'),
        change: (pos, oldData, newData) => print('change on $pos from $oldData to $newData'),
        move: (from, to, data) => print('move $data from $from to $to'),
      );
    }

Note that if you implement you own DiffDelegate and call calculateDiff() directly, the DiffDelegate also needs to implement IndexableItemDiffDelegate if you want to call getUpdatesWithData().

Change Operations

For data objects that have some meaningful identity (like an unique id field), you can enable the calculation of Change operations. For this, you need to implement your own DiffDelegate and override the areItemsTheSame method.

Let's say we have a class called DataObject which is defined like this:


class DataObject {
  final int id;
  final int? payload;

  DataObject({required this.id, this.payload});
}

The delegate can be implemented like this:

class DataObjectListDiff extends diffutil.ListDiffDelegate<DataObject> {
  DataObjectListDiff(List<DataObject> oldList, List<DataObject> newList)
      : super(oldList, newList);

  @override
  bool areContentsTheSame(int oldItemPosition, int newItemPosition) {
    return equalityChecker(oldList[oldItemPosition], newList[newItemPosition]);
  }

  @override
  bool areItemsTheSame(int oldItemPosition, int newItemPosition) {
    return oldList[oldItemPosition].id == newList[newItemPosition].id;
  }
}

With this, Change Operations are emitted if the id of an object stays the same between oldList and newList, but it's data changes.

Performance metrics:

Same as Android's DiffUtil:

  • O(N) space
  • O(N + D^2) time performance where D is the length of the edit script.
  • additional O(N^2) time where N is the total number of added and removed items if move detection is enabled

The edit script is the smallest set of operations needed to transform the first list into the second list.

カテゴリー

ソースリポジトリ

このパッケージを使用しているプロジェクト