UICollectionView添加手勢(shì),可以使cell移動(dòng)、添加、刪除,這種功能網(wǎng)上也有一大堆的資料可供查看,本文沒(méi)有做封裝,提供一個(gè)思路給讀者;封裝的再好,不符合自己的業(yè)務(wù),還是需要修改的;
仿支付寶的效果,你可以打開(kāi)支付寶,首頁(yè)中有個(gè)全部功能,點(diǎn)擊進(jìn)去,第一個(gè)分區(qū)的cell是可以移動(dòng),第一個(gè)分區(qū)可以添加,可以刪除;后面的分區(qū)不可以添加,也不能夠刪除和移動(dòng),如果第一個(gè)分區(qū)已經(jīng)有了,下面的就是一個(gè)??
號(hào),如果沒(méi)有,則顯示+
號(hào);第一個(gè)分區(qū)永遠(yuǎn)都是-
號(hào),表示只能刪除;
首先創(chuàng)建一個(gè)繼承與UICollectionViewFlowLayout
的類(lèi):.h中的代碼
#import <UIKit/UIKit.h>
@protocol SYLifeManagerDelegate <NSObject>
/**
* 改變編輯狀態(tài)
*/
- (void)didChangeEditState:(BOOL)inEditState;
/**
* 更新數(shù)據(jù)源
*/
- (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; //當(dāng)前indexPath
@property (nonatomic, assign) CGPoint movePoint; //移動(dòng)的中心點(diǎn)
@property (nonatomic, strong) UIView *moveView; //移動(dòng)的視圖
@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 - 長(zhǎng)按手勢(shì)
- (void)setUpGestureRecognizers
{
if (self.collectionView == nil) {
return;
}
[self.collectionView addGestureRecognizer:self.longGesture];
}
#pragma mark - 手勢(shì)動(dòng)畫(huà)
- (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];
//得到當(dāng)前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];
//使用代理方法更新數(shù)據(jù)源
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 - 處于編輯狀態(tài)
- (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 - 手勢(shì)
- (UILongPressGestureRecognizer *)longGesture
{
if (!_longGesture) {
_longGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longGesture:)];
_longGesture.minimumPressDuration = 0.5f; //時(shí)間長(zhǎng)短
_longGesture.delegate = self;
}
return _longGesture;
}
@end
限于文章篇幅長(zhǎng)度,有需要的可以移步demo,demo里面有很多注釋?zhuān)绻睦镉袉?wèn)題,可以交流;
SYLifeManagerCell
創(chuàng)建的cell,這個(gè)就不用多講了,一般都是一張圖片和描述文案
SYLifeManagerModel
創(chuàng)建的model
SYLifeManagerHeaderView
是創(chuàng)建的區(qū)頭視圖,為了顯示分區(qū)標(biāo)題
SYLIfeManagerFooterView
是區(qū)尾視圖,主要是為了實(shí)現(xiàn)分割線(xiàn)
Demo的Github地址,如果有問(wèn)題或者好的建議,希望留言,歡迎交流!