搜尋套件、儲存庫與 APP 分類

套件詳情v5.0.0

diffutil_dart

將兩個列表之間的差異計算為一組編輯操作。例如,用於在無需維護 StatefulWidget 的情況下隱式動畫化 Flutter 列表。

AndroidiOSWebmacOSWindowsLinux
近 30 天下載
21.9萬
喜歡數
104
Pub 分數
160

安裝套件

flutter pub add diffutil_dart

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

diffutil_dart 計算兩個清單之間的差異,並產生一系列編輯操作(插入、刪除、移動),以將一個清單轉換為另一個清單。這使得在 Flutter 列表中實現高效、隱式動畫成為可能,而無需手動管理 StatefulWidget 小部件中的狀態。它特別適用於使用動態資料更新 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.

所屬分類

原始碼儲存庫

使用此套件的專案