Skip to content

Instantly share code, notes, and snippets.

@EvoIos
Last active December 2, 2020 07:59
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EvoIos/aee7497ee845b9083a737ba1d718172e to your computer and use it in GitHub Desktop.
Save EvoIos/aee7497ee845b9083a737ba1d718172e to your computer and use it in GitHub Desktop.
UICollectionViewCell siwpe left to delete, or custom reveal button
#import <UIKit/UIKit.h>
extern NSString * const SwipeCollectionViewCurrentSwipeCell;
@interface ZLCSwipeCollectionViewCell : UICollectionViewCell
@property (nonatomic,strong) UIView *revealView;
/// default: YES, if you want to disable panGestureRecoginzer, you can use this property.
@property (nonatomic,assign) BOOL canSwiped;
/// optional: when only use default revealView, you maybe set this property, eg: xxx.deleteButtonTitle = @"delete"
@property (nonatomic,copy) NSString *deleteButtonTitle;
/// optional: when only use default revealView, you can use this function
@property (nonatomic,copy) void(^zlc_delete)(void);
- (void)hideRevealViewAnimated:(BOOL)isAnimated;
@end
#import "ZLCSwipeCollectionViewCell.h"
#import <objc/runtime.h>
@interface UIView (SuperCollectionView)
- (UICollectionView *)zlc_superCollectionView;
@end
@implementation UIView (SuperCollectionView)
- (UICollectionView *)zlc_superCollectionView {
UIView *superview = self.superview;
while (superview != nil) {
if ([superview isKindOfClass:[UICollectionView class]]) {
return (id)superview;
}
superview = [superview superview];
}
return nil;
}
@end
NSString * const SwipeCollectionViewCurrentSwipeCell = @"currentSwipeCell";
@interface ZLCSwipeCollectionViewCell()<UIGestureRecognizerDelegate>
@property (nonatomic,strong) UIView *snapShotView;
@property (nonatomic,strong) UIView *snapBackgroundView;
@property (nonatomic,strong) UIPanGestureRecognizer *panGesture;
@end
@implementation ZLCSwipeCollectionViewCell
- (void)prepareForReuse {
[super prepareForReuse];
[self.snapBackgroundView removeFromSuperview];
self.snapBackgroundView = nil;
[self.snapShotView removeFromSuperview];
self.snapShotView = nil;
[self.revealView removeFromSuperview];
}
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.canSwiped = YES;
[self configureGestureRecognizer];
}
return self;
}
- (void)configureGestureRecognizer {
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(zlc_panAction:)];
self.panGesture.delegate = self;
[self addGestureRecognizer:self.panGesture];
}
- (void)layoutSubviews {
[super layoutSubviews];
self.revealView.frame = (CGRect) {
.origin = CGPointMake( CGRectGetWidth(self.frame) - CGRectGetWidth(self.revealView.frame), 0.0f),
.size = self.revealView.frame.size
};
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer isMemberOfClass:[UIPanGestureRecognizer class]]) {
UIPanGestureRecognizer *gesture = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint point = [gesture velocityInView:self];
if (fabs(point.x) > fabs(point.y)) {
return YES;
}
}
return NO;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return otherGestureRecognizer != self.zlc_superCollectionView.panGestureRecognizer;
}
- (void)setCanSwiped:(BOOL)canSwiped {
_canSwiped = canSwiped;
self.panGesture.enabled = canSwiped;
}
#pragma mark - event response
- (void)zlc_deleteAction:(UIButton *)sender {
[self hideRevealViewAnimated:YES];
if (self.zlc_delete) {
self.zlc_delete();
}
}
- (void)zlc_panAction:(UIPanGestureRecognizer *)panGesture {
switch (panGesture.state) {
case UIGestureRecognizerStateBegan: {
[self _closeOtherOpeningCell];
[self addSubview:self.snapBackgroundView];
[self addSubview:self.revealView];
[self addSubview:self.snapShotView];
}
break;
case UIGestureRecognizerStateChanged: {
CGPoint translationPoint = [panGesture translationInView:self];
CGPoint centerPoint = CGPointMake(0, self.snapShotView.center.y);
centerPoint.x = MIN(CGRectGetWidth(self.frame)/2 ,
self.snapShotView.center.x + translationPoint.x);;
[panGesture setTranslation:CGPointZero inView:self];
self.snapShotView.center = centerPoint;
}
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
CGPoint velocity = [panGesture velocityInView:self];
if ([self _bigThenRevealViewHalfWidth] || [self _shouldShowRevealViewForVelocity:velocity]) {
[self showRevealViewAnimated:YES];
}
if ([self _lessThenRevealViewHalfWidth] || [self _shouldHideRevealViewForVelocity:velocity]) {
if (CGPointEqualToPoint(self.snapShotView.center, self.center)) { return; }
[self hideRevealViewAnimated:YES];
}
}
break;
default:
break;
}
}
- (BOOL)_shouldHideRevealViewForVelocity:(CGPoint)velocity {
return fabs(velocity.x) > CGRectGetWidth(self.revealView.frame)/2 && velocity.x > 0;
}
- (BOOL)_shouldShowRevealViewForVelocity:(CGPoint)velocity {
return fabs(velocity.x) > CGRectGetWidth(self.revealView.frame)/2 && velocity.x < 0;
}
- (BOOL)_bigThenRevealViewHalfWidth {
return fabs(CGRectGetMinX(self.snapShotView.frame)) >= CGRectGetWidth(self.revealView.frame)/2;
}
- (BOOL)_lessThenRevealViewHalfWidth {
return fabs(CGRectGetMinX(self.snapShotView.frame)) < CGRectGetWidth(self.revealView.frame)/2;
}
- (void)showRevealViewAnimated:(BOOL)isAnimated {
[UIView animateWithDuration:isAnimated ? 0.1: 0
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.snapShotView.center = CGPointMake( CGRectGetWidth(self.frame)/2 - CGRectGetWidth(self.revealView.frame),
self.snapShotView.center.y );
}
completion:^(BOOL finished) {
}];
}
- (void)hideRevealViewAnimated:(BOOL)isAnimated {
[UIView animateWithDuration:isAnimated ? 0.1: 0
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^{
self.snapShotView.center = CGPointMake( CGRectGetWidth(self.frame)/2,
self.snapShotView.center.y );
}
completion:^(BOOL finished) {
[self.snapBackgroundView removeFromSuperview];
self.snapBackgroundView = nil;
[self.snapShotView removeFromSuperview];
self.snapShotView = nil;
[self.revealView removeFromSuperview];
}];
}
- (void)_closeOtherOpeningCell {
if (self.zlc_superCollectionView) {
ZLCSwipeCollectionViewCell *currentCell = objc_getAssociatedObject(self.zlc_superCollectionView,(__bridge const void *)(SwipeCollectionViewCurrentSwipeCell));
if (currentCell != self) {
[currentCell hideRevealViewAnimated:YES];
}
objc_setAssociatedObject(self.zlc_superCollectionView, (__bridge const void *)(SwipeCollectionViewCurrentSwipeCell), self, OBJC_ASSOCIATION_ASSIGN);
}
}
#pragma mark - lazy
- (UIView *)snapBackgroundView {
if (!_snapBackgroundView) {
_snapBackgroundView = ({
UIView *tmpView = [[UIView alloc] initWithFrame:self.bounds];
tmpView.backgroundColor = [UIColor whiteColor];
tmpView;
});
}
return _snapBackgroundView;
}
- (UIView *)snapShotView {
if (!_snapShotView) {
_snapShotView = [self snapshotViewAfterScreenUpdates:NO];
}
return _snapShotView;
}
- (UIView *)revealView {
if (!_revealView) {
_revealView = ({
UIView *tmpView = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width - 55, 0, 55, self.frame.size.height)];
tmpView.backgroundColor = [UIColor clearColor];
tmpView;
});
UIButton *deleteButton = ({
UIButton *tmpBtn = [[UIButton alloc] initWithFrame:_revealView.bounds];
[tmpBtn setTitle:self.deleteButtonTitle == nil? @"删除":self.deleteButtonTitle forState:UIControlStateNormal];
[tmpBtn addTarget:self action:@selector(zlc_deleteAction:) forControlEvents:UIControlEventTouchUpInside];
[tmpBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[tmpBtn setBackgroundColor:[UIColor colorWithRed:255/255.0 green:58/255.0 blue:58/255.0 alpha:1]];
tmpBtn.titleLabel.font = [UIFont systemFontOfSize:18];
tmpBtn;
});
[_revealView addSubview:deleteButton];
}
return _revealView;
}
@end
@EvoIos
Copy link
Author

EvoIos commented Jul 16, 2017

use

only one step: subclass ZLCSwipeCollectionViewCell , then you can use swipe left to delete in UICollectionView.

Attention

  • there is only one opened cell in global collectionView
  • you can custom reveal view for you self.
  • maybe you want change the reveal button title, you need to set deleteButtonTitle property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment