Flutter | WReorderList 一個可以指定兩個item互換位置的元件

Flutter筆記發表於2019-08-21

最近遇到個需求,要求在一個 ListView 裡面能互換兩個 item 的位置,這樣:

Flutter | WReorderList 一個可以指定兩個item互換位置的元件

於是,就有了現在的這個 WReorderList

WReorderList

功能就不用多說了,可以隨意替換兩個 item 的位置。

建構函式及其用法

還是按照老規矩,先來看一下建構函式:

WReorderList({
  Key key,
  @required this.children,
  @required this.onIndexChanged,
  this.duration = const Duration(milliseconds: 500)
}) : super(key: key);
複製程式碼

一共四個引數:

  1. key:不用多說
  2. children:子元件集合
  3. onIndexChanged:當兩個位置變化之後的回撥,要更改您自己的資料來源
  4. duration:動畫時間

怎麼用就很簡單了:

WReorderList(
  key: key,
  children: children,
  onIndexChanged: (a, b) {
    setState(() {
      var temp = _colors[a];
      _colors[a] = _colors[b];
      _colors[b] = temp;
    });
  },
),
複製程式碼

元件用上了, 那如何交換位置呢?

有兩種方法:

  1. WReorderList 設定一個 GlobalKey,然後 key.currentState.swap(0, 1) 就OK了
  2. 通過 WReorderList.of(context) 方法獲取到 state,然後再呼叫 swap 方法就好了。

WReorderList 原理解析

分析原理

首先從技術角度分析一下:

  1. 怎麼交換兩個 item 位置?
  2. 如何獲取到需要交換的兩個 item 的元件
  3. 交換過程中兩個 item 原來的位置上要被空白佔用?

怎麼交換兩個 item 位置

這裡我原本預想了好幾種方案:

  1. 彈出一個Overlay,在 Overlay 上做動畫
  2. 彈出一個 PopupRoute,用 Hero 動畫
  3. 染出一個 PopupRoute,在上面做動畫

第一種方案被否決了,因為我 Overlay 用的不是很多。

第二種我試了一下,發現 Hero 不能用,所以也否了。

那就只剩第三種了,我試了一下用 AnimatedPositioned,發現是可以的,那就決定是他了。

如何獲取到需要交換的兩個 item 的元件

這個我原本也想過用 GlobalKey,但是在列表中有一大堆的 GlobalKey 又不好,

所以我定義了一個類,該類如下:

class WReorderData {
  Widget widget;
  BuildContext context;
  double height;

  WReorderData(this.widget);
}
複製程式碼

在使用者傳進來 children 以後,就用該類包住,獲取到他的widget。

並且在 build 的時候用 Builder 包裹住就可以獲取到當前這個 widget 的 context了。

就能獲取到需要交換的兩個 item 的位置。

交換過程中兩個 item 原來的位置上要被空白佔用?

可以看到最開始的效果中,交換過程中是被空白給佔用了的,那這個高度如何獲取?

我查了一下資料,發現這種是個有效的方法:

在 build 的時候加上一個 Future.delayed,100毫秒之後用當前 context 獲取高度,這樣就ok了。

程式碼如下:

Builder(builder: (context) {
  Future.delayed(Duration(milliseconds: 100), () {
    data[index].context = context;
    data[index].height = context.size.height;
  });
  return swapIndex.contains(index)
    ? Container(height: data[index].height)
    : data[index].widget;
});
複製程式碼

總結

最近通過PopupRoute 已經定義了兩個元件了,感覺還是很有用的。

有個需要注意的點是:使用 WReorderList.of(context) 方法來獲取 State 的話,一定要在子元件中,否則會找不到 state!!!

程式碼已上傳至 GitHub:github.com/fluttercand…

並且釋出控制元件到了 Pub:pub.dev/packages/w_…

另我個人建立了一個「Flutter 交流群」,可以新增我個人微信 「17610912320」來入群。

推薦閱讀:

Flutter | 思路解析 WPopupMenu 仿微信聊天長按彈出選單

Flutter | 一個關於背景顏色引發的打臉慘案

Flutter | 自定義一個 Stepper 步驟元件

img

相關文章