效果圖
UICollectionView添加手勢,可以使cell移動、添加、刪除,這種功能網上也有一大堆的資料可供查看,本文沒有做封裝,提供一個思路給讀者;封裝的再好,不符合自己的業務,還是需要修改的;
仿支付寶的效果,你可以打開支付寶,首頁中有個全部功能,點擊進去,第一個分區的cell是可以移動,第一個分區可以添加,可以刪除;后面的分區不可以添加,也不能夠刪除和移動,如果第一個分區已經有了,下面的就是一個??
號,如果沒有,則顯示+
號;第一個分區永遠都是-
號,表示只能刪除;
首先創建一個繼承與UICollectionViewFlowLayout
的類:.h中的代碼
#import <UIKit/UIKit.h>
@protocol SYLifeManagerDelegate <NSObject>
/**
* 改變編輯狀態
*/
- (void)didChangeEditState:(BOOL)inEditState;
/**
* 更新數據源
*/
- (void)moveItemAtIndexPath:(NSIndexPath *)formPath toIndexPath:(NSIndexPath *)toPath;
@end
@interface SYLifeManagerLayout : UICollectionViewFlowLayout
@property (nonatomic, assign) BOOL inEditState;
@property (nonatomic, assign) id<SYLifeManagerDelegate> delegate;
@end
.m中的代碼:
#import "SYLifeManagerLayout.h"
#import "SYLifeManagerCell.h"
#import "SYLifeManagerModel.h"
#import "Header.h"
@interface SYLifeManagerLayout ()<UIGestureRecognizerDelegate>
@property (nonatomic, strong) UILongPressGestureRecognizer *longGesture;
@property (nonatomic, strong) NSIndexPath *currentIndexPath; //當前indexPath
@property (nonatomic, assign) CGPoint movePoint; //移動的中心點
@property (nonatomic, strong) UIView *moveView; //移動的視圖
@end
@implementation SYLifeManagerLayout
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self configureObserver];
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
[self configureObserver];
}
return self;
}
#pragma mark - 添加觀察者
- (void)configureObserver
{
[self addObserver:self forKeyPath:@"collectionView" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if ([keyPath isEqualToString:@"collectionView"]) {
[self setUpGestureRecognizers];
} else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - 長按手勢
- (void)setUpGestureRecognizers
{
if (self.collectionView == nil) {
return;
}
[self.collectionView addGestureRecognizer:self.longGesture];
}
#pragma mark - 手勢動畫
- (void)longGesture:(UILongPressGestureRecognizer *)gesture
{
if (!self.inEditState) {
[self setInEditState:YES];
}
switch (gesture.state) {
case UIGestureRecognizerStateBegan: {
CGPoint location = [gesture locationInView:self.collectionView];
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:location];
//如果indexPath為空,不做任何操作
if (indexPath == nil || indexPath.section != 0) return;
self.currentIndexPath = indexPath;
UICollectionViewCell *targetCell = [self.collectionView cellForItemAtIndexPath:self.currentIndexPath];
//得到當前cell的映射(截圖)
self.moveView = [targetCell snapshotViewAfterScreenUpdates:YES];
self.moveView.layer.borderWidth = 0.3;
self.moveView.layer.borderColor = [UIColor sy_grayColor].CGColor;
[self.collectionView addSubview:self.moveView];
targetCell.hidden = YES;
self.moveView.transform = CGAffineTransformMakeScale(1.1, 1.1);
self.moveView.center = location;
}
break;
case UIGestureRecognizerStateChanged: {
CGPoint point = [gesture locationInView:self.collectionView];
//更新cell的位置
self.moveView.center = point;
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:point];
if (indexPath == nil) return;
if (indexPath.section == self.currentIndexPath.section && indexPath.section == 0) {
[self.collectionView moveItemAtIndexPath:self.currentIndexPath toIndexPath:indexPath];
//使用代理方法更新數據源
if ([self.delegate respondsToSelector:@selector(moveItemAtIndexPath:toIndexPath:)]) {
[self.delegate moveItemAtIndexPath:self.currentIndexPath toIndexPath:indexPath];
}
self.currentIndexPath = indexPath;
}
}
break;
case UIGestureRecognizerStateEnded: {
UICollectionViewCell *cell = [self.collectionView cellForItemAtIndexPath:self.currentIndexPath];
[UIView animateWithDuration:0.25 animations:^{
self.moveView.center = cell.center;
} completion:^(BOOL finished) {
[self.moveView removeFromSuperview];
cell.hidden = NO;
self.moveView = nil;
self.currentIndexPath = nil;
[self.collectionView reloadData];
}];
}
break;
default:
break;
}
}
#pragma mark - 處于編輯狀態
- (void)setInEditState:(BOOL)inEditState
{
if (_inEditState != inEditState) {
if (_delegate && [_delegate respondsToSelector:@selector(didChangeEditState:)]) {
[_delegate didChangeEditState:inEditState];
}
}
_inEditState = inEditState;
}
#pragma mark - 移除觀察者
- (void)dealloc
{
[self removeObserver:self forKeyPath:@"collectionView"];
}
#pragma mark - 手勢
- (UILongPressGestureRecognizer *)longGesture
{
if (!_longGesture) {
_longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGesture:)];
_longGesture.minimumPressDuration = 0.5f; //時間長短
_longGesture.delegate = self;
}
return _longGesture;
}
@end
限于文章篇幅長度,有需要的可以移步demo,demo里面有很多注釋,如果哪里有問題,可以交流;
SYLifeManagerCell
創建的cell,這個就不用多講了,一般都是一張圖片和描述文案
SYLifeManagerModel
創建的model
SYLifeManagerHeaderView
是創建的區頭視圖,為了顯示分區標題
SYLIfeManagerFooterView
是區尾視圖,主要是為了實現分割線
Demo的Github地址,如果有問題或者好的建議,希望留言,歡迎交流!