GridView 拖拽图标列表实现插入删除动画效果(一)
平移动画
Flutter 提供了四个Widget可实现平移动画,分别是
- SlideTransition
- AlignTransition
- PositionedTransition
- ReleativePositionedTransition
我们采用第一种 SlideTransition SlideTransition基于 Animation 来确定平移位置。平移的具体距离,由Widget自身的宽高 * Offset中的 x,y 值
AnimationController _slideController =
AnimationController(duration: const Duration(milliseconds: 300), vsync: this);
Animation<Offset> animate =
Tween(begin: const Offset(0, 0), end: const Offset(1, 1)).animate(_slideController);
return SlideTransition(position: animate, child: child);
这样就能实现目标Widget 从原点移动到右下角自身宽高的距离,学会使用平移动画之后,只要在拖拽目标移动时,判断出每一个Widget需要移动到什么位置,就能实现插入删除效果了
Flutter 拖拽效果
拖拽组件
class Draggable<T extends Object> extends StatefulWidget{}
Draggable<Item>(
onDragStarted: () {
// 开始拖拽 删除拖拽的item 然后开始删除动画
},
onDraggableCanceled: (v, o) {
},
data: item,
feedback: ,
dragAnchorStrategy: pointerDragAnchorStrategy,
child: child,
),
接收组件
class DragTarget<T extends Object> extends StatefulWidget {}
DragTarget<Item>(
onAccept: (item) {
// 降拖拽组件插入到当前位置,刷新
}
onWillAccept: (item) {
// 开始插入动画
},
builder: (context, candidateItems, rejectedItems) {
return child;
},
);
核心算法
我们把每一个GirdView中的item项都看做是一个DragTarget,然后在将要接受拖拽组件时,计算出每一个widget将移动的offset 例 : list = [1,2,3,4,5,6] 我们正在拖拽的item为7 假如gridview 是一个3列的列表 那么 list当前的排列是这样的
当我们把7放到3上,那么新的排列应该是什么样的?
list = [1,2,3,4,5,6]
remainsList = [1,2,7,3,4,5,6]
animate = createTargetItemSlideAnimation(2)
Animation<Offset>? createTargetItemSlideAnimation(int index) {
int? targetIndex;
if (remainsList.contains(list[index])) {
targetIndex = remainsList.indexOf(list[index]);
}
if (targetIndex != null && index != targetIndex) {
return Tween(begin: const Offset(0, 0), end: getTargetOffset(index, targetIndex)).animate(_slideController);
} else {
return null;
}
}
Offset getTargetOffset(int startIndex, int endIndex) {
int horizontalCount = 3;
int horizontalIndex = endIndex % horizontalCount - startIndex % horizontalCount;
int verticalIndex = endIndex ~/ horizontalCount - startIndex ~/ horizontalCount;
double dx = horizontalIndex.toDouble();
double dy = verticalIndex.toDouble();
return Offset(dx, dy);
}
这样就能获取每一个widget应该移动的offset了 接着调用_slideController.forward().whenComplete((){})就可以开始动画并在动画结束后做出相应的逻辑了
下一期给出源码