2
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
// 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.
|
||||
|
||||
////////////////////
|
||||
/// v3.1.4
|
||||
////////////////////
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "BMLongPressDragCellCollectionViewDelegate.h"
|
||||
#import "BMLongPressDragCellCollectionViewDataSource.h"
|
||||
|
||||
/*
|
||||
- (NSArray<NSArray<id> *> *)dataSourceWithDragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView {
|
||||
return self.dataSourceArray;
|
||||
// 此协议方法里返回数据源
|
||||
}
|
||||
|
||||
- (void)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView newDataArrayAfterMove:(nullable NSArray <NSArray <id> *> *)newDataArray {
|
||||
self.dataSourceArray = [newDataArray mutableCopy];
|
||||
// 此协议方法里保存数据源
|
||||
}
|
||||
*/
|
||||
@interface BMLongPressDragCellCollectionView : UICollectionView
|
||||
|
||||
@property (nonatomic, weak) id<BMLongPressDragCellCollectionViewDelegate> delegate;
|
||||
@property (nonatomic, weak) id<BMLongPressDragCellCollectionViewDataSource> dataSource;
|
||||
|
||||
/// 长按触发拖拽所需时间,默认是 0.5 秒。
|
||||
@property (nonatomic, assign) NSTimeInterval minimumPressDuration;
|
||||
|
||||
/// 是否可以拖拽 默认为 YES。
|
||||
@property (nonatomic, assign, getter=isCanDrag) IBInspectable BOOL canDrag;
|
||||
|
||||
/// 长按拖拽时拖拽中的的 Cell 缩放比例,默认是 1.2 倍。
|
||||
@property (nonatomic, assign) IBInspectable CGFloat dragZoomScale;
|
||||
|
||||
/// 拖拽的 Cell 在拖拽移动时的透明度 默认是: 1.0 不透明。
|
||||
@property (nonatomic, assign) IBInspectable CGFloat dragCellAlpha;
|
||||
|
||||
/// 拖拽到 UICollectionView 边缘时 UICollectionView 的滚动速度
|
||||
/// 默认为: 8.0f ,建议设置 5.0f 到 15.0f 之间。
|
||||
@property (nonatomic, assign) IBInspectable CGFloat dragSpeed;
|
||||
|
||||
/// 拖拽 View 的背景颜色,默认和被拖拽的 Cell 一样。
|
||||
@property (nonatomic, strong) IBInspectable UIColor *dragSnapedViewBackgroundColor;
|
||||
|
||||
/// 移动到指定位置
|
||||
/// @param indexPath 移动到的位置
|
||||
/// 内部只会处理当前正在拖拽的情况,会把拖拽的 Cell 移动到指定位置,建议在停止手势时或者认为适当的时候使用。
|
||||
- (void)dragMoveItemToIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,729 @@
|
||||
// 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
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class BMLongPressDragCellCollectionView;
|
||||
|
||||
@protocol BMLongPressDragCellCollectionViewDataSource <UICollectionViewDataSource>
|
||||
|
||||
@required
|
||||
|
||||
/**
|
||||
获取数据源,内部会在合适的时候获取最新的数据源,必须实现
|
||||
|
||||
@param dragCellCollectionView dragCellCollectionView
|
||||
@return 最新的数据源
|
||||
|
||||
- (nullable NSArray *)dataSourceWithDragCellCollectionView:(BMLongPressDragCellCollectionView *)dragCellCollectionView {
|
||||
return self.dataArray;
|
||||
}
|
||||
*/
|
||||
- (nullable NSArray <NSArray <id> *> *)dataSourceWithDragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,98 @@
|
||||
// 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 <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class BMLongPressDragCellCollectionView;
|
||||
|
||||
@protocol BMLongPressDragCellCollectionViewDelegate <UICollectionViewDelegateFlowLayout>
|
||||
|
||||
@required
|
||||
|
||||
/**
|
||||
Cell 有交换时调用
|
||||
|
||||
@param dragCellCollectionView dragCellCollectionView
|
||||
@param newDataArray 最新的数据源,需要使用者保存,在拖拽的时候 Cell 已经移动,需保存最新的数据源
|
||||
|
||||
- (void)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView newDataArrayAfterMove:(nullable NSArray <NSArray <id> *> *)newDataArray {
|
||||
self.dataArray = [newDataArray copy];
|
||||
}
|
||||
*/
|
||||
- (void)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView newDataArrayAfterMove:(nullable NSArray <NSArray <id> *> *)newDataArray;
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
将要开始拖拽时,询问此位置的 Cell 是否能拖拽
|
||||
|
||||
@param dragCellCollectionView dragCellCollectionView
|
||||
@param indexPath indexPath
|
||||
@return YES: 正常拖拽和移动 NO:此 Cell 不可拖拽,如:增加按钮等。
|
||||
*/
|
||||
- (BOOL)dragCellCollectionViewShouldBeginMove:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView indexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/**
|
||||
将要开始拖拽时,向外面获取需要拖拽的 View,如果不实现就内部自动处理。
|
||||
|
||||
@param dragCellCollectionView dragCellCollectionView
|
||||
@param indexPath indexPath
|
||||
@return dragView
|
||||
*/
|
||||
- (UIView *)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView startDragAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/// 开始拖拽时,让外面的使用者可以对拖拽的 View 做额外操作
|
||||
/// @param dragCellCollectionView dragCellCollectionView
|
||||
/// @param dragView dragView
|
||||
/// @param indexPath indexPath
|
||||
- (void)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView dragView:(UIView *)dragView indexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/// 正在拖拽时
|
||||
/// @param dragCellCollectionView dragCellCollectionView
|
||||
/// @param point 手指触摸点对于 collectionView 的位置
|
||||
/// 可以参考 https://github.com/liangdahong/ToutiaoDemo/blob/master/ToutiaoDemo/Classes/Edit/Controller/BMChannelEditVC.m 的使用
|
||||
- (void)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView changedDragAtPoint:(CGPoint)point;
|
||||
|
||||
/// cell 将要交换时,询问是否能交换
|
||||
/// @param dragCellCollectionView dragCellCollectionView
|
||||
/// @param sourceIndexPath 原来的 IndexPath
|
||||
/// @param destinationIndexPath 将要交换的 IndexPath
|
||||
/// YES: 正常拖拽和移动 NO:此Cell不可拖拽,如:增加按钮等。
|
||||
- (BOOL)dragCellCollectionViewShouldBeginExchange:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView sourceIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
|
||||
|
||||
/// 结束交换时
|
||||
/// @param dragCellCollectionView dragCellCollectionView
|
||||
/// @param sourceIndexPath 原来的 IndexPath
|
||||
/// @param destinationIndexPath 被交换的 IndexPath
|
||||
- (void)dragCellCollectionViewShouldEndExchange:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView sourceIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
|
||||
|
||||
/// 结束拖拽时
|
||||
/// @param dragCellCollectionView dragCellCollectionView
|
||||
/// @param point 手指触摸点对于 collectionView 的位置
|
||||
/// 可以参考 https://github.com/liangdahong/ToutiaoDemo/blob/master/ToutiaoDemo/Classes/Edit/Controller/BMChannelEditVC.m 的使用
|
||||
- (void)dragCellCollectionView:(__kindof BMLongPressDragCellCollectionView *)dragCellCollectionView endedDragAtPoint:(CGPoint)point;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
Reference in New Issue
Block a user