Files
keyboard/keyBoard/Class/Vender/BMLongPressDragCellCollectionView/BMLongPressDragCellCollectionView.m
2025-11-10 20:40:11 +08:00

730 lines
29 KiB
Objective-C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// MIT License
//
// Copyright (c) 2019 https://liangdahong.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "BMLongPressDragCellCollectionView.h"
typedef NS_ENUM(NSUInteger, BMLongPressDragCellCollectionViewScrollDirection) {
BMLongPressDragCellCollectionViewScrollDirectionNone = 0,
BMLongPressDragCellCollectionViewScrollDirectionLeft = 1,
BMLongPressDragCellCollectionViewScrollDirectionRight = 2,
BMLongPressDragCellCollectionViewScrollDirectionUp = 3,
BMLongPressDragCellCollectionViewScrollDirectionDown = 4,
};
@interface BMLongPressDragCellCollectionView ()
/// 长按手势
@property (nonatomic, strong, nullable) UILongPressGestureRecognizer *longGesture;
/// 截图快照
@property (nonatomic, strong, nullable) UIView *snapedView;
/// 定时器
@property (nonatomic, strong, nullable) CADisplayLink *edgeTimer;
/// 旧的IndexPath
@property (nonatomic, strong, nullable) NSIndexPath *oldIndexPath;
/// 当前路径
@property (nonatomic, strong, nullable) NSIndexPath *currentIndexPath;
@property (nonatomic, assign) BOOL isEndDrag; ///< 是否已经停止拖动
@property (nonatomic, assign) BOOL banReload; ///< 禁止刷新
@property (nonatomic, assign) CGPoint oldPoint; ///< 旧的位置
@property (nonatomic, assign) CGPoint lastPoint; ///< 最后的触摸点
@end
@implementation BMLongPressDragCellCollectionView
@dynamic delegate, dataSource;
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
if (self = [super initWithFrame:frame collectionViewLayout:layout]) {
[self initConfiguration];
}
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[self initConfiguration];
}
return self;
}
- (void)dealloc {
[self _stopEdgeTimer];
}
#pragma mark - getters setters
- (void)setCanDrag:(BOOL)canDrag {
_canDrag = canDrag;
self.longGesture.enabled = _canDrag;
}
- (void)setMinimumPressDuration:(NSTimeInterval)minimumPressDuration {
_minimumPressDuration = minimumPressDuration;
self.longGesture.minimumPressDuration = minimumPressDuration;
}
- (void)setDragZoomScale:(CGFloat)dragZoomScale {
if (dragZoomScale < 0.1) {
dragZoomScale = 1.2;
}
_dragZoomScale = dragZoomScale;
}
- (void)setDragSpeed:(CGFloat)dragSpeed {
if (dragSpeed < 0.5) {
dragSpeed = 8.0;
}
_dragSpeed = dragSpeed;
}
- (void)setDragSnapedViewBackgroundColor:(UIColor *)dragSnapedViewBackgroundColor {
_dragSnapedViewBackgroundColor = dragSnapedViewBackgroundColor;
_snapedView.backgroundColor = dragSnapedViewBackgroundColor;
}
- (UILongPressGestureRecognizer *)longGesture {
if (!_longGesture) {
_longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlelongGesture:)];
_longGesture.minimumPressDuration = _minimumPressDuration;
}
return _longGesture;
}
// iOS 10 新特性 对UICollectionView做了优化但是这里如果使用了会导致bug,重写此方法是为了让其无法修改
// https://developer.apple.com/documentation/uikit/uicollectionview/1771771-prefetchingenabled
// https://sxgfxm.github.io/blog/2016/10/18/uicollectionview-ios10-new-features
- (void)setPrefetchingEnabled:(BOOL)prefetchingEnabled {
[super setPrefetchingEnabled:NO];
}
#pragma mark - 私有方法
- (void)initConfiguration {
_canDrag = YES;
_minimumPressDuration = 0.5;
_dragZoomScale = 1.2;
_dragCellAlpha = 1.0;
_dragSpeed = 8.0;
[self addGestureRecognizer:self.longGesture];
// iOS 10 新特性 对 UICollectionView 做了优化但是这里如果使用了会导致bug
// https://developer.apple.com/documentation/uikit/uicollectionview/1771771-prefetchingenabled
// https://sxgfxm.github.io/blog/2016/10/18/uicollectionview-ios10-new-features
if (@available(iOS 10.0, *)) {
self.prefetchingEnabled = NO;
}
}
- (void)reloadData {
if (_banReload) {
return;
}
[super reloadData];
}
- (void)insertSections:(NSIndexSet *)sections {
if (_banReload) {
return;
}
[super insertSections:sections];
}
- (void)deleteSections:(NSIndexSet *)sections {
if (_banReload) {
return;
}
[super deleteSections:sections];
}
- (void)reloadSections:(NSIndexSet *)sections {
if (_banReload) {
return;
}
[super reloadSections:sections];
}
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection {
if (_banReload) {
return;
}
[super moveSection:section toSection:newSection];
}
- (void)insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
if (_banReload) {
return;
}
[super insertItemsAtIndexPaths:indexPaths];
}
- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
if (_banReload) {
return;
}
[super deleteItemsAtIndexPaths:indexPaths];
}
- (void)reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
if (_banReload) {
return;
}
[super reloadItemsAtIndexPaths:indexPaths];
}
- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath {
if (_banReload) {
return;
}
[super moveItemAtIndexPath:indexPath toIndexPath:newIndexPath];
}
- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [super dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
// 处理复用时的问题,为了保证显示的正确性
if (_isEndDrag) {
cell.hidden = NO;
} else {
cell.hidden = (self.oldIndexPath
&& self.oldIndexPath.item == indexPath.item
&& self.oldIndexPath.section == indexPath.section);
}
return cell;
}
- (nullable NSIndexPath *)_getChangedNullIndexPath {
__block NSIndexPath *index = nil;
CGPoint point = [self.longGesture locationInView:self];
NSInteger number = self.numberOfSections;
while (number--) {
NSInteger row = [self.dataSource collectionView:self numberOfItemsInSection:number];
if (row == 0) {
// 如果这组是空的
CGRect headerFrame = [self layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:number]].frame;
CGRect footerFrame = [self layoutAttributesForSupplementaryElementOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:number]].frame;
CGRect frame = CGRectZero;
if (((UICollectionViewFlowLayout *)self.collectionViewLayout).scrollDirection == UICollectionViewScrollDirectionHorizontal) {
// 水平方向
frame = CGRectMake(CGRectGetMinX(headerFrame),
CGRectGetMinY(headerFrame),
CGRectGetMaxX(footerFrame) - CGRectGetMidX(headerFrame),
CGRectGetWidth(footerFrame));
if (frame.size.width < 10.0) {
// 如果这组的宽度小于 10.0,就设置一个默认值 10.0,主要是为了判断触摸点缩放在这组内。
frame.size.width = 10.0;
frame.size.height = CGRectGetHeight(self.frame);
frame.origin.x -= 5.0;
}
} else {
// 垂直方向
frame = CGRectMake(CGRectGetMinX(headerFrame),
CGRectGetMinY(headerFrame),
CGRectGetWidth(footerFrame),
CGRectGetMaxY(footerFrame) - CGRectGetMidY(headerFrame));
if (frame.size.height < 10.0) {
// 如果这组的高度小于 10.0,就设置一个默认值 10.0,主要是为了判断触摸点缩放在这组内。
frame.size.height = 10.0;
frame.size.width = CGRectGetWidth(self.frame);
frame.origin.y -= 5.0;
}
}
if (CGRectContainsPoint(frame, point)) {
// 触摸点在空的组内
return [NSIndexPath indexPathForItem:0 inSection:number];
}
}
}
return index;
}
- (nullable NSIndexPath *)_getChangedIndexPath {
__block NSIndexPath *index = nil;
CGPoint point = [self.longGesture locationInView:self];
// 遍历拖拽的 Cell 的中心点在哪一个 Cell 里
[[self visibleCells] enumerateObjectsUsingBlock:^(__kindof UICollectionViewCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (CGRectContainsPoint(obj.frame, point)) {
index = [self indexPathForCell:obj];
*stop = YES;
}
}];
// 找到而且不是当前的 Cell 就返回此 index
if (index) {
if ((index.section == self.oldIndexPath.section) && (index.item == self.oldIndexPath.item)) {
return nil;
}
return index;
}
// 获取最应该交换的 Cell
__block CGFloat width = MAXFLOAT;
__weak typeof(self) weakSelf = self;
[[self visibleCells] enumerateObjectsUsingBlock:^(__kindof UICollectionViewCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (CGRectContainsPoint(obj.frame, point)) {
index = [self indexPathForCell:obj];
*stop = YES;
}
__strong typeof(weakSelf) self = weakSelf;
CGPoint p1 = self.snapedView.center;
CGPoint p2 = obj.center;
// 计算距离
CGFloat distance = sqrt(pow((p1.x - p2.x), 2) + pow((p1.y - p2.y), 2));
if (distance < width) {
width = distance;
index = [self indexPathForCell:obj];
}
}];
if (!index) {
return nil;
}
if ((index.section == self.oldIndexPath.section) && (index.item == self.oldIndexPath.item)) {
// 最近的就是隐藏的 Cell 时, return nil
return nil;
}
return index;
}
// 处理临界点问题
- (BMLongPressDragCellCollectionViewScrollDirection)_setScrollDirection {
if (((self.bounds.size.height + self.contentOffset.y - _snapedView.center.y) < (_snapedView.bounds.size.height / 2))
&& ((self.bounds.size.height + self.contentOffset.y) < self.contentSize.height)) {
return BMLongPressDragCellCollectionViewScrollDirectionDown;
} else if (((_snapedView.center.y - self.contentOffset.y) < (_snapedView.bounds.size.height / 2))
&& self.contentOffset.y > 0) {
return BMLongPressDragCellCollectionViewScrollDirectionUp;
} else if (((self.bounds.size.width + self.contentOffset.x) - (_snapedView.center.x)) < (_snapedView.bounds.size.width / 2)
&& (self.bounds.size.width + self.contentOffset.x) < self.contentSize.width) {
return BMLongPressDragCellCollectionViewScrollDirectionRight;
} else if (((_snapedView.center.x - self.contentOffset.x) < (_snapedView.bounds.size.width) / 2)
&& self.contentOffset.x > 0) {
return BMLongPressDragCellCollectionViewScrollDirectionLeft;
}
return BMLongPressDragCellCollectionViewScrollDirectionNone;
}
// 处理 UICollectionView 数据源
- (void)_updateSourceData {
// 获取数据源
NSMutableArray *array = [self.dataSource dataSourceWithDragCellCollectionView:self].mutableCopy;
// 处理数据
BOOL dataTypeCheck = ([self numberOfSections] != 1 || ([self numberOfSections] == 1 && [array[0] isKindOfClass:NSArray.class]));
if (dataTypeCheck) {
for (int i = 0; i < array.count; i ++) {
// 如果是嵌套数组 就把数组里面的数组换为 NSMutableArray。
[array replaceObjectAtIndex:i withObject:[array[i] mutableCopy]];
}
}
if (_currentIndexPath.section == _oldIndexPath.section) {
NSMutableArray *orignalSection = dataTypeCheck ? array[_oldIndexPath.section] : array;
if (_currentIndexPath.item > _oldIndexPath.item) {
for (NSUInteger i = _oldIndexPath.item; i < _currentIndexPath.item ; i ++) {
[orignalSection exchangeObjectAtIndex:i withObjectAtIndex:i + 1];
}
} else {
for (NSUInteger i = _oldIndexPath.item; i > _currentIndexPath.item ; i --) {
[orignalSection exchangeObjectAtIndex:i withObjectAtIndex:i - 1];
}
}
} else {
NSMutableArray *orignalSection = array[_oldIndexPath.section];
NSMutableArray *currentSection = array[_currentIndexPath.section];
[currentSection insertObject:orignalSection[_oldIndexPath.item] atIndex:_currentIndexPath.item];
// https://github.com/liangdahong/BMLongPressDragCellCollectionView/issues/16
// 这里之前删除指定对象会有问题,如果数据源中的对象为 [字符串 而且是一样的时候, 因为 OC 中对字符串的内存做了特殊处理 ],会把相同的字符串全部删除导致崩溃
// [orignalSection removeObject:orignalSection[_oldIndexPath.item]];
[orignalSection removeObjectAtIndex:_oldIndexPath.item];
}
// ==========处理数据
// 更新外面的数据源
// 这里会触发外面的使用者修改数据源,但外面的使用者可以会在此调用 reloadData 相关方法,所以做了拦截操作
// https://github.com/liangdahong/BMLongPressDragCellCollectionView/issues/14
self.banReload = YES;
[self.delegate dragCellCollectionView:self newDataArrayAfterMove:array];
self.banReload = NO;
}
- (void)_setEdgeTimer{
if (!_edgeTimer) {
_edgeTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(_edgeScroll)];
[_edgeTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
}
- (void)_stopEdgeTimer{
if (_edgeTimer) {
[_edgeTimer invalidate];
_edgeTimer = nil;
}
}
- (void)_edgeScroll {
BMLongPressDragCellCollectionViewScrollDirection scrollDirection = [self _setScrollDirection];
if (BMLongPressDragCellCollectionViewScrollDirectionNone == scrollDirection) {
return;
}
switch (scrollDirection) {
case BMLongPressDragCellCollectionViewScrollDirectionLeft:{
// 这里的动画必须设为 NO
[self setContentOffset:CGPointMake(self.contentOffset.x - _dragSpeed, self.contentOffset.y) animated:NO];
_snapedView.center = CGPointMake(_snapedView.center.x - _dragSpeed, _snapedView.center.y);
_lastPoint.x -= _dragSpeed;
}
break;
case BMLongPressDragCellCollectionViewScrollDirectionRight:{
[self setContentOffset:CGPointMake(self.contentOffset.x + _dragSpeed, self.contentOffset.y) animated:NO];
_snapedView.center = CGPointMake(_snapedView.center.x + _dragSpeed, _snapedView.center.y);
_lastPoint.x += _dragSpeed;
}
break;
case BMLongPressDragCellCollectionViewScrollDirectionUp:{
[self setContentOffset:CGPointMake(self.contentOffset.x, self.contentOffset.y - _dragSpeed) animated:NO];
_snapedView.center = CGPointMake(_snapedView.center.x, _snapedView.center.y - _dragSpeed);
_lastPoint.y -= _dragSpeed;
}
break;
case BMLongPressDragCellCollectionViewScrollDirectionDown:{
[self setContentOffset:CGPointMake(self.contentOffset.x, self.contentOffset.y + _dragSpeed) animated:NO];
_snapedView.center = CGPointMake(_snapedView.center.x, _snapedView.center.y + _dragSpeed);
_lastPoint.y += _dragSpeed;
}
break;
default:
break;
}
// 如果Cell 拖拽到了边沿时
// 截图视图位置移动
[UIView animateWithDuration:0.1 animations:^{
self.snapedView.center = self.lastPoint;
}];
// 获取应该交换的 Cell 的位置
NSIndexPath *index1 = [self _getChangedNullIndexPath];
NSIndexPath *index = nil;
index = index1 ? : [self _getChangedIndexPath];
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionView:changedDragAtPoint:)]) {
[self.delegate dragCellCollectionView:self changedDragAtPoint:_lastPoint];
}
if (!index) {
return;
}
// 是否可以交换
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionViewShouldBeginExchange:sourceIndexPath:toIndexPath:)]) {
if (![self.delegate dragCellCollectionViewShouldBeginExchange:self sourceIndexPath:_oldIndexPath toIndexPath:index]) {
return;
}
}
_currentIndexPath = index;
UICollectionViewCell *cell1 = [self cellForItemAtIndexPath:_currentIndexPath];
NSIndexPath *sourceIndexPath = _oldIndexPath;
NSIndexPath *toIndexPath = _currentIndexPath;
if (!index1) {
self.oldPoint = cell1.center;
// 更新数据源
[self _updateSourceData];
// 移动 cell
[self moveItemAtIndexPath:_oldIndexPath toIndexPath:_currentIndexPath];
// 设置移动后的起始 indexPath
_oldIndexPath = _currentIndexPath;
// 为了防止在缓存池取出的 Cell 已隐藏,
// 以后可以优化
[self reloadItemsAtIndexPaths:@[_oldIndexPath]];
} else {
// 更新数据源
[self _updateSourceData];
// 移动 cell
[self moveItemAtIndexPath:_oldIndexPath toIndexPath:_currentIndexPath];
self.oldPoint = [self cellForItemAtIndexPath:_currentIndexPath].center;
// 设置移动后的起始 indexPath
_oldIndexPath = _currentIndexPath;
[self reloadItemsAtIndexPaths:@[_oldIndexPath]];
}
// 交换结束时
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionViewShouldEndExchange:sourceIndexPath:toIndexPath:)]) {
[self.delegate dragCellCollectionViewShouldEndExchange:self sourceIndexPath:sourceIndexPath toIndexPath:toIndexPath];
}
}
#pragma mark - 事件响应
- (void)handlelongGesture:(UILongPressGestureRecognizer *)longGesture {
CGPoint point = [longGesture locationInView:self];
NSIndexPath *indexPath = [self indexPathForItemAtPoint:point];
switch (longGesture.state) {
case UIGestureRecognizerStateBegan: {
// 手势开始
self.userInteractionEnabled = NO;
_oldIndexPath = indexPath;
// 判断手势落点位置是否在 Cell 上, 没有按在 cell 上就 break
if (_oldIndexPath == nil) {
self.longGesture.enabled = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.canDrag) {
self.longGesture.enabled = YES;
}
});
break;
}
// 将要开始拖拽时询问此位置的Cell是否可以拖拽
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionViewShouldBeginMove:indexPath:)]) {
if (![self.delegate dragCellCollectionViewShouldBeginMove:self indexPath:_oldIndexPath]) {
_oldIndexPath = nil;
self.longGesture.enabled = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.canDrag) {
self.longGesture.enabled = YES;
}
});
break;
}
}
self.isEndDrag = NO;
// 取出正在长按的cell
UICollectionViewCell *cell = [self cellForItemAtIndexPath:_oldIndexPath];
self.oldPoint = cell.center;
// 先置 nil
if (_snapedView) {
_snapedView = nil;
}
// 是否外部提供拖拽View
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionView: startDragAtIndexPath:)]) {
_snapedView = [self.delegate dragCellCollectionView:self startDragAtIndexPath:indexPath];
}
if (!_snapedView) {
// 使用系统截图功能,得到 cell 的快照 view
_snapedView = [cell snapshotViewAfterScreenUpdates:NO];
}
// 修改颜色
if (_dragSnapedViewBackgroundColor) {
_snapedView.backgroundColor = _dragSnapedViewBackgroundColor;
}
// 让外面做一些特殊处理
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionView: dragView:indexPath:)]) {
[self.delegate dragCellCollectionView:self dragView:_snapedView indexPath:indexPath];
}
// 设置frame
_snapedView.frame = cell.frame;
// 添加到 collectionView 不然无法显示
[self addSubview:_snapedView];
// 截图后隐藏当前 cell
cell.hidden = YES;
// 获取当前触摸的中心点
CGPoint currentPoint = point;
// 动画放大和移动到触摸点下面
[UIView animateWithDuration:0.25 animations:^{
self.snapedView.transform = CGAffineTransformMakeScale(self.dragZoomScale, self.dragZoomScale);
self.snapedView.center = CGPointMake(currentPoint.x, currentPoint.y);
self.snapedView.alpha = self.dragCellAlpha;
}];
}
break;
case UIGestureRecognizerStateChanged: {
// 开启 collectionView 的边缘自动滚动检测
// https://github.com/liangdahong/BMLongPressDragCellCollectionView/issues/15
if (!_edgeTimer) {
[self _setEdgeTimer];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionView:changedDragAtPoint:)]) {
[self.delegate dragCellCollectionView:self changedDragAtPoint:point];
}
// 当前手指位置
_lastPoint = point;
// 截图视图位置移动
[UIView animateWithDuration:0.1 animations:^{
self.snapedView.center = self.lastPoint;
}];
NSIndexPath *index1 = [self _getChangedNullIndexPath];
NSIndexPath *index = nil;
if (index1) {
index = index1;
} else {
index = [self _getChangedIndexPath];
}
// 没有取到 || 距离隐藏的 Cell 最近时就返回
if (!index) {
break;
}
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionViewShouldBeginExchange:sourceIndexPath:toIndexPath:)]) {
if (![self.delegate dragCellCollectionViewShouldBeginExchange:self sourceIndexPath:_oldIndexPath toIndexPath:index]) {
break;
}
}
_currentIndexPath = index;
UICollectionViewCell *cell1 = [self cellForItemAtIndexPath:_currentIndexPath];
NSIndexPath *sourceIndexPath = _oldIndexPath;
NSIndexPath *toIndexPath = _currentIndexPath;
if (!index1) {
self.oldPoint = cell1.center;
// 更新数据源
[self _updateSourceData];
// 移动 cell
[self moveItemAtIndexPath:_oldIndexPath toIndexPath:_currentIndexPath];
// 设置移动后的起始 indexPath
_oldIndexPath = _currentIndexPath;
[self reloadItemsAtIndexPaths:@[_oldIndexPath]];
} else {
// 更新数据源
[self _updateSourceData];
// 移动 cell
[self moveItemAtIndexPath:_oldIndexPath toIndexPath:_currentIndexPath];
self.oldPoint = [self cellForItemAtIndexPath:_currentIndexPath].center;
// 设置移动后的起始 indexPath
_oldIndexPath = _currentIndexPath;
[self reloadItemsAtIndexPaths:@[_oldIndexPath]];
}
// 交换结束时
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionViewShouldEndExchange:sourceIndexPath:toIndexPath:)]) {
[self.delegate dragCellCollectionViewShouldEndExchange:self sourceIndexPath:sourceIndexPath toIndexPath:toIndexPath];
}
break;
}
break;
default: {
self.userInteractionEnabled = YES;
if (self.delegate && [self.delegate respondsToSelector:@selector(dragCellCollectionView:endedDragAtPoint:)]) {
[self.delegate dragCellCollectionView:self endedDragAtPoint:point];
}
if (longGesture.isEnabled) {
if (!self.oldIndexPath) {
return;
}
UICollectionViewCell *cell = [self cellForItemAtIndexPath:_oldIndexPath];
// 结束动画过程中停止交互,防止出问题
self.userInteractionEnabled = NO;
// 结束拖拽了
self.isEndDrag = YES;
// 给截图视图一个动画移动到隐藏 cell 的新位置
[UIView animateWithDuration:0.25 animations:^{
if (!cell) {
self.snapedView.center = self.oldPoint;
} else {
self.snapedView.center = cell.center;
}
self.snapedView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
self.snapedView.alpha = 1.0;
} completion:^(BOOL finished) {
// 移除截图视图、显示隐藏的 cell 并开启交互
[self.snapedView removeFromSuperview];
self.snapedView = nil;
cell.hidden = NO;
self.userInteractionEnabled = YES;
}];
}
// 关闭定时器
self.oldIndexPath = nil;
[self _stopEdgeTimer];
}
break;
}
}
- (void)dragMoveItemToIndexPath:(NSIndexPath *)newIndexPath {
if (self.isEndDrag) {
return;
}
self.isEndDrag = YES;
self.longGesture.enabled = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.canDrag) {
self.longGesture.enabled = YES;
}
});
if (_oldIndexPath) {
_currentIndexPath = newIndexPath;
// 更新数据源
[self _updateSourceData];
// 移动 cell
[self moveItemAtIndexPath:_oldIndexPath toIndexPath:_currentIndexPath];
// 设置移动后的起始 indexPath
_oldIndexPath = newIndexPath;
[self reloadItemsAtIndexPaths:@[newIndexPath]];
UICollectionViewCell *cell = [self cellForItemAtIndexPath:_oldIndexPath];
cell.hidden = YES;
// 结束动画过程中停止交互,防止出问题
self.userInteractionEnabled = NO;
// 结束拖拽了
self.isEndDrag = YES;
// 给截图视图一个动画移动到隐藏 cell 的新位置
[UIView animateWithDuration:0.25 animations:^{
if (!cell) {
self.snapedView.center = self.oldPoint;
} else {
self.snapedView.center = cell.center;
}
self.snapedView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
self.snapedView.alpha = 1.0;
} completion:^(BOOL finished) {
// 移除截图视图、显示隐藏的 cell 并开启交互
[self.snapedView removeFromSuperview];
cell.hidden = NO;
self.userInteractionEnabled = YES;
}];
}
// 关闭定时器
_oldIndexPath = nil;
[self _stopEdgeTimer];
}
@end