本次学习的MCSwipeTableViewCell的效果如图:
MCSwipeTableViewCell是表视图单元格上滑动手势的运用,类似Mailbox App的。可自定义颜色和图标,默认滑动删除内容。要求iOS 5及以上版本,支持ARC。
一、MCSwipeTableViewCell的使用
1.首先将MCSwipeTableViewCell的.m和.h文件与相应的图片文件夹导入
2.创建tableView并实现其代理
3.返回单元格的方法实现
//返回单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
MCSwipeTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[MCSwipeTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
[cell setSelectionStyle:UITableViewCellSelectionStyleGray];
cell.contentView.backgroundColor = [UIColor whiteColor];
}
//配置单元格
[self configureCell:cell forRowAtIndexPath:indexPath];
return cell;
}
4.配置单元格的方法实现
//配置单元格
- (void)configureCell:(MCSwipeTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
//设置选中视图
UIView *checkView = [self viewWithImageName:@"check"];
UIColor *greenColor = [UIColor colorWithRed:85.0 / 255.0 green:213.0 / 255.0 blue:80.0 / 255.0 alpha:1.0];
//设置删除视图
UIView *crossView = [self viewWithImageName:@"cross"];
UIColor *redColor = [UIColor colorWithRed:232.0 / 255.0 green:61.0 / 255.0 blue:14.0 / 255.0 alpha:1.0];
//设置定时提醒视图
UIView *clockView = [self viewWithImageName:@"clock"];
UIColor *yellowColor = [UIColor colorWithRed:254.0 / 255.0 green:217.0 / 255.0 blue:56.0 / 255.0 alpha:1.0];
//设置列表视图
UIView *listView = [self viewWithImageName:@"list"];
UIColor *brownColor = [UIColor colorWithRed:206.0 / 255.0 green:149.0 / 255.0 blue:98.0 / 255.0 alpha:1.0];
//设置默认的背景颜色
[cell setDefaultColor:_tableView.backgroundView.backgroundColor];
//设置单元格的代理
[cell setDelegate:self];
//设置每个单元格的实现效果
//第一个单元格
if (indexPath.row % kMCNumItems == 0) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Switch Mode Cell"];
[cell.detailTextLabel setText:@"Swipe to switch"];
//设置单元格的选中视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:checkView color:greenColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState1 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Checkmark\" cell");
}];
//设置单元格的删除视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:crossView color:redColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState2 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Cross\" cell");
}];
//设置单元格的定时视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:clockView color:yellowColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState3 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Clock\" cell");
}];
//设置单元格的列表视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:listView color:brownColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState4 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"List\" cell");
}];
}
//第二个单元格
else if (indexPath.row % kMCNumItems == 1) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Exit Mode Cell"];
[cell.detailTextLabel setText:@"Swipe to delete"];
//设置单元格的删除视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:crossView color:redColor mode:MCSwipeTableViewCellModeExit state:MCSwipeTableViewCellState1 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Cross\" cell");
[self deleteCell:cell];
}];
}
//第三个单元格
else if (indexPath.row % kMCNumItems == 2) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Mixed Mode Cell"];
[cell.detailTextLabel setText:@"Swipe to switch or delete"];
//设置单元格的选中视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:checkView color:greenColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState1 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Checkmark\" cell");
}];
//设置单元格的删除视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:crossView color:redColor mode:MCSwipeTableViewCellModeExit state:MCSwipeTableViewCellState2 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Cross\" cell");
[self deleteCell:cell];
}];
}
//第四个单元格
else if (indexPath.row % kMCNumItems == 3) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Un-animated Icons"];
[cell.detailTextLabel setText:@"Swipe"];
//设置图标是否移动
cell.shouldAnimateIcons = NO;
//设置单元格的选中视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:checkView color:greenColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState1 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Checkmark\" cell");
}];
//设置单元格的删除视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:crossView color:redColor mode:MCSwipeTableViewCellModeExit state:MCSwipeTableViewCellState2 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Cross\" cell");
[self deleteCell:cell];
}];
}
//第五个单元格
else if (indexPath.row % kMCNumItems == 4) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Right swipe only"];
[cell.detailTextLabel setText:@"Swipe"];
//设置单元格的定时视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:clockView color:yellowColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState3 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Clock\" cell");
}];
//设置单元格的列表视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:listView color:brownColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState4 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"List\" cell");
}];
}
//第六个单元格
else if (indexPath.row % kMCNumItems == 5) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Small triggers"];
[cell.detailTextLabel setText:@"Using 10% and 50%"];
//设置第一个触发事件的距离百分比
cell.firstTrigger = 0.1;
//设置第二个触发事件的距离百分比
cell.secondTrigger = 0.5;
//设置单元格的选中视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:checkView color:greenColor mode:MCSwipeTableViewCellModeSwitch state:MCSwipeTableViewCellState1 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Checkmark\" cell");
}];
//设置单元格的删除视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:crossView color:redColor mode:MCSwipeTableViewCellModeExit state:MCSwipeTableViewCellState2 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Cross\" cell");
[self deleteCell:cell];
}];
}
//第七个单元格
else if (indexPath.row % kMCNumItems == 6) {
//设置单元格的主标题、副标题
[cell.textLabel setText:@"Exit Mode Cell + Confirmation"];
[cell.detailTextLabel setText:@"Swipe to delete"];
//设置单元格的删除视图、颜色、状态、完成后的block
[cell setSwipeGestureWithView:crossView color:redColor mode:MCSwipeTableViewCellModeExit state:MCSwipeTableViewCellState1 completionBlock:^(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode) {
NSLog(@"Did swipe \"Cross\" cell");
//设置要删除的单元格
_cellToDelete = cell;
//创建弾框
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"删除?"
message:@"你确定要删除这个单元格?"
delegate:self
cancelButtonTitle:@"否"
otherButtonTitles:@"是", nil];
[alertView show];
}];
}
}
5.创建图片视图
//创建图片视图
- (UIView *)viewWithImageName:(NSString *)imageName {
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.contentMode = UIViewContentModeCenter;
return imageView;
}
6.UIAlertViewDelegate的实现
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
//选择“否”
if (buttonIndex == 0) {
[_cellToDelete swipeToOriginWithCompletion:^{
NSLog(@"选择否");
}];
_cellToDelete = nil;
}
//选择"是“
else {
//删除单元格
_nbItems--;//剩余单元格数
[_tableView deleteRowsAtIndexPaths:@[[_tableView indexPathForCell:_cellToDelete]] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)deleteCell:(MCSwipeTableViewCell *)cell {
//删除单元格
_nbItems--;<span style="font-family: Arial, Helvetica, sans-serif;">//剩余单元格数</span>
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
[_tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
- (IBAction)reload:(UIBarButtonItem *)sender {
//重新加载单元格
_nbItems = kMCNumItems; //<span style="font-family: Arial, Helvetica, sans-serif;">kMCNumItems默认单元格数</span>
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}
8.单元格的代理实现
//监听手指滑动的开始
- (void)swipeTableViewCellDidStartSwiping:(MCSwipeTableViewCell *)cell {
NSLog(@"开始滑动单元格!");
}
//监听手指滑动的结束
- (void)swipeTableViewCellDidEndSwiping:(MCSwipeTableViewCell *)cell {
NSLog(@"结束滑动单元格!");
}
//监听手指滑动的距离
- (void)swipeTableViewCell:(MCSwipeTableViewCell *)cell
didSwipeWithPercentage:(CGFloat)percentage {
NSLog(@"已滑动百分比 : %.2f%%", percentage*100);
}
二、MCSwipeTableViewCell的实现原理
1.MCSwipeTableViewCell.h文件
//
// MCSwipeTableViewCell.h
// MCSwipeTableViewCell
//
// Created by Ali Karagoz on 24/02/13.
// Copyright (c) 2014 Ali Karagoz. All rights reserved.
//
#import
@class MCSwipeTableViewCell;
/** Describes the state that has been triggered by the user. */
typedef NS_OPTIONS(NSUInteger, MCSwipeTableViewCellState) {
//不开启任何事件
MCSwipeTableViewCellStateNone = 0,
//开启从左向右滑动的第一个事件
MCSwipeTableViewCellState1 = (1 << 0),
//开启从左向右滑动的第二个事件
MCSwipeTableViewCellState2 = (1 << 1),
//开启从右向左滑动的第一个事件
MCSwipeTableViewCellState3 = (1 << 2),
//开启从右向左滑动的第二个事件
MCSwipeTableViewCellState4 = (1 << 3)
};
/** Describes the mode used during a swipe */
typedef NS_ENUM(NSUInteger, MCSwipeTableViewCellMode) {
//设置当前事件不可触发
MCSwipeTableViewCellModeNone = 0,
//事件触发后设置为当前选中的状态
MCSwipeTableViewCellModeExit,
//事件触发后自动返回
MCSwipeTableViewCellModeSwitch
};
/**
* `MCSwipeCompletionBlock`
*
* @param cell 当前单元格
* @param state 要开启的触发事件
* @param mode 事件的触发效果
*
* @return No return value.
*/
typedef void (^MCSwipeCompletionBlock)(MCSwipeTableViewCell *cell, MCSwipeTableViewCellState state, MCSwipeTableViewCellMode mode);
@protocol MCSwipeTableViewCellDelegate;
@interface MCSwipeTableViewCell : UITableViewCell
//单元格的代理
@property (nonatomic, assign) id delegate;
/**
* Damping 滑动的百分比
*
* @discussion Only applied for version of iOS > 7.
*/
@property (nonatomic, assign, readwrite) CGFloat damping;
/**
* Velocity 滑动的速度
*
* @discussion Only applied for version of iOS > 7.
*/
@property (nonatomic, assign, readwrite) CGFloat velocity;
//动画持续时间
@property (nonatomic, assign, readwrite) NSTimeInterval animationDuration;
//默认的背景颜色
@property (nonatomic, strong, readwrite) UIColor *defaultColor;
//从左向右滑动的第一个事件的视图背景颜色
@property (nonatomic, strong, readwrite) UIColor *color1;
//从左向右滑动的第二个事件的视图背景颜色
@property (nonatomic, strong, readwrite) UIColor *color2;
//从右向左滑动的第一个事件的视图背景颜色
@property (nonatomic, strong, readwrite) UIColor *color3;
//从右向左滑动的第二个事件的视图背景颜色
@property (nonatomic, strong, readwrite) UIColor *color4;
//从左向右滑动的第一个事件的视图
@property (nonatomic, strong, readwrite) UIView *view1;
//从左向右滑动的第二个事件的视图
@property (nonatomic, strong, readwrite) UIView *view2;
//从右向左滑动的第一个事件的视图
@property (nonatomic, strong, readwrite) UIView *view3;
//从右向左滑动的第二个事件的视图
@property (nonatomic, strong, readwrite) UIView *view4;
//从左向右滑动的第一个事件的block
@property (nonatomic, copy, readwrite) MCSwipeCompletionBlock completionBlock1;
//从左向右滑动的第二个事件的block
@property (nonatomic, copy, readwrite) MCSwipeCompletionBlock completionBlock2;
//从右向左滑动的第一个事件的block
@property (nonatomic, copy, readwrite) MCSwipeCompletionBlock completionBlock3;
//从右向左滑动的第二个事件的block
@property (nonatomic, copy, readwrite) MCSwipeCompletionBlock completionBlock4;
// Percentage of when the first and second action are activated, respectively
//触发第一个事件的距离百分比
@property (nonatomic, assign, readwrite) CGFloat firstTrigger;
//触发第二个事件的距离百分比
@property (nonatomic, assign, readwrite) CGFloat secondTrigger;
//从左向右滑动的第一个事件的触发效果
@property (nonatomic, assign, readwrite) MCSwipeTableViewCellMode modeForState1;
//从左向右滑动的第二个事件的触发效果
@property (nonatomic, assign, readwrite) MCSwipeTableViewCellMode modeForState2;
//从右向左滑动的第一个事件的触发效果
@property (nonatomic, assign, readwrite) MCSwipeTableViewCellMode modeForState3;
//从右向左滑动的第二个事件的触发效果
@property (nonatomic, assign, readwrite) MCSwipeTableViewCellMode modeForState4;
//判断是否是当前滑动的单元格
@property (nonatomic, assign, readonly, getter=isDragging) BOOL dragging;
//单元格是否有滑动的资格
@property (nonatomic, assign, readwrite) BOOL shouldDrag;
//状态图标是够有滑动的资格
@property (nonatomic, assign, readwrite) BOOL shouldAnimateIcons;
/**
* Configures the properties of a cell.
*
* @param view 触发事件的视图
* @param color 触发事件的视图颜色
* @param mode 触发事件的触发后的效果
* @param state 触发事件的选择
* @param completionBlock 完成后执行的block
*/
- (void)setSwipeGestureWithView:(UIView *)view
color:(UIColor *)color
mode:(MCSwipeTableViewCellMode)mode
state:(MCSwipeTableViewCellState)state
completionBlock:(MCSwipeCompletionBlock)completionBlock;
/**
* 滑动回初始状态
*
* @param completion 返回之后执行的block
*/
- (void)swipeToOriginWithCompletion:(void(^)(void))completion;
@end
@protocol MCSwipeTableViewCellDelegate
@optional
/**
* 监听滑动的开始
*
* @param cell 当前滑动的单元格
*/
- (void)swipeTableViewCellDidStartSwiping:(MCSwipeTableViewCell *)cell;
/**
* 监听滑动的结束
*
* @param cell 当前滑动的单元格
*/
- (void)swipeTableViewCellDidEndSwiping:(MCSwipeTableViewCell *)cell;
/**
* 监听滑动
*
* @param cell 当前滑动的单元格
* @param percentage 滑动的百分比
*/
- (void)swipeTableViewCell:(MCSwipeTableViewCell *)cell didSwipeWithPercentage:(CGFloat)percentage;
@end
2.MCSwipeTableViewCell.m文件
//
// MCSwipeTableViewCell.m
// MCSwipeTableViewCell
//
// Created by Ali Karagoz on 24/02/13.
// Copyright (c) 2014 Ali Karagoz. All rights reserved.
//
#import "MCSwipeTableViewCell.h"
static CGFloat const kMCStop1 = 0.25; // 第一个事件触发的距离百分比
static CGFloat const kMCStop2 = 0.75; // 第二个事件触发的距离百分比
static CGFloat const kMCBounceAmplitude = 20.0; //反弹速度
static CGFloat const kMCDamping = 0.6; // ????
static CGFloat const kMCVelocity = 0.9; // 反弹动画的速度
static CGFloat const kMCAnimationDuration = 0.4; // 反弹动画的持续时间
static NSTimeInterval const kMCBounceDuration1 = 0.2; // 反弹第一部分的动画持续时间
static NSTimeInterval const kMCBounceDuration2 = 0.1; // 反弹第二部分的动画持续时间
static NSTimeInterval const kMCDurationLowLimit = 0.25; // 最慢反弹时间
static NSTimeInterval const kMCDurationHighLimit = 0.1; // 最快反弹时间
typedef NS_ENUM(NSUInteger, MCSwipeTableViewCellDirection) {
MCSwipeTableViewCellDirectionLeft = 0,
MCSwipeTableViewCellDirectionCenter,
MCSwipeTableViewCellDirectionRight
};
@interface MCSwipeTableViewCell ()
@property (nonatomic, assign) MCSwipeTableViewCellDirection direction;
@property (nonatomic, assign) CGFloat currentPercentage; //当前滑动的距离百分比
@property (nonatomic, assign) BOOL isExited; //是否有选中的状态
@property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer; //滑动手势
@property (nonatomic, strong) UIImageView *contentScreenshotView; //当前单元格的图片
@property (nonatomic, strong) UIView *colorIndicatorView; //颜色视图
@property (nonatomic, strong) UIView *slidingView; //滑动视图
@property (nonatomic, strong) UIView *activeView; //活跃视图
// 初始化
- (void)initializer;
- (void)initDefaults;
// 视图的创建
- (void)setupSwipingView;
- (void)uninstallSwipingView;
- (void)setViewOfSlidingView:(UIView *)slidingView;
// 距离百分比
- (CGFloat)offsetWithPercentage:(CGFloat)percentage relativeToWidth:(CGFloat)width;
- (CGFloat)percentageWithOffset:(CGFloat)offset relativeToWidth:(CGFloat)width;
- (NSTimeInterval)animationDurationWithVelocity:(CGPoint)velocity;
- (MCSwipeTableViewCellDirection)directionWithPercentage:(CGFloat)percentage;
- (UIView *)viewWithPercentage:(CGFloat)percentage;
- (CGFloat)alphaWithPercentage:(CGFloat)percentage;
- (UIColor *)colorWithPercentage:(CGFloat)percentage;
- (MCSwipeTableViewCellState)stateWithPercentage:(CGFloat)percentage;
// 移动
- (void)animateWithOffset:(CGFloat)offset;
- (void)slideViewWithPercentage:(CGFloat)percentage view:(UIView *)view isDragging:(BOOL)isDragging;
- (void)moveWithDuration:(NSTimeInterval)duration andDirection:(MCSwipeTableViewCellDirection)direction;
// Utilities
- (UIImage *)imageWithView:(UIView *)view;
// Completion block.
- (void)executeCompletionBlock;
@end
@implementation MCSwipeTableViewCell
#pragma mark - Initialization
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self initializer];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self initializer];
}
return self;
}
- (id)init {
self = [super init];
if (self) {
[self initializer];
}
return self;
}
- (void)initializer {
[self initDefaults];
// 创建滑动手势
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGestureRecognizer:)];
[self addGestureRecognizer:_panGestureRecognizer];
_panGestureRecognizer.delegate = self;
}
//设置初始化状态
- (void)initDefaults {
_isExited = NO;
_dragging = NO;
_shouldDrag = YES;
_shouldAnimateIcons = YES;
_firstTrigger = kMCStop1;
_secondTrigger = kMCStop2;
_damping = kMCDamping;
_velocity = kMCVelocity;
_animationDuration = kMCAnimationDuration;
_defaultColor = [UIColor whiteColor];
_modeForState1 = MCSwipeTableViewCellModeNone;
_modeForState2 = MCSwipeTableViewCellModeNone;
_modeForState3 = MCSwipeTableViewCellModeNone;
_modeForState4 = MCSwipeTableViewCellModeNone;
_color1 = nil;
_color2 = nil;
_color3 = nil;
_color4 = nil;
_activeView = nil;
_view1 = nil;
_view2 = nil;
_view3 = nil;
_view4 = nil;
}
#pragma mark - Prepare reuse
- (void)prepareForReuse {
[super prepareForReuse];
[self uninstallSwipingView];
[self initDefaults];
}
#pragma mark - View Manipulation
- (void)setupSwipingView {
if (_contentScreenshotView) {
return;
}
// 设置背景颜色
BOOL isContentViewBackgroundClear = !self.contentView.backgroundColor;
if (isContentViewBackgroundClear) {
//如果contentView没有背景颜色
BOOL isBackgroundClear = [self.backgroundColor isEqual:[UIColor clearColor]];
//如果背景颜色为透明 contentView的背景颜色设置为白色 否则设置为背景颜色
self.contentView.backgroundColor = isBackgroundClear ? [UIColor whiteColor] :self.backgroundColor;
}
//将当前单元格的样子绘成图片
UIImage *contentViewScreenshotImage = [self imageWithView:self];
_colorIndicatorView = [[UIView alloc] initWithFrame:self.bounds];
_colorIndicatorView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
_colorIndicatorView.backgroundColor = self.defaultColor ? self.defaultColor : [UIColor clearColor];
[self addSubview:_colorIndicatorView];
_slidingView = [[UIView alloc] init];
_slidingView.contentMode = UIViewContentModeCenter;
[_colorIndicatorView addSubview:_slidingView];
_contentScreenshotView = [[UIImageView alloc] initWithImage:contentViewScreenshotImage];
[self addSubview:_contentScreenshotView];
}
//滑动结束后删除视图
- (void)uninstallSwipingView {
if (!_contentScreenshotView) {
return;
}
[_slidingView removeFromSuperview];
_slidingView = nil;
[_colorIndicatorView removeFromSuperview];
_colorIndicatorView = nil;
[_contentScreenshotView removeFromSuperview];
_contentScreenshotView = nil;
}
- (void)setViewOfSlidingView:(UIView *)slidingView {
if (!_slidingView) {
return;
}
NSArray *subviews = [_slidingView subviews];
[subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
[view removeFromSuperview];
}];
[_slidingView addSubview:slidingView];
}
#pragma mark - Swipe configuration
- (void)setSwipeGestureWithView:(UIView *)view
color:(UIColor *)color
mode:(MCSwipeTableViewCellMode)mode
state:(MCSwipeTableViewCellState)state
completionBlock:(MCSwipeCompletionBlock)completionBlock {
NSParameterAssert(view);
NSParameterAssert(color);
// 设置触发事件的视图,颜色,状态,block
if ((state & MCSwipeTableViewCellState1) == MCSwipeTableViewCellState1) {
_completionBlock1 = completionBlock;
_view1 = view;
_color1 = color;
_modeForState1 = mode;
}
if ((state & MCSwipeTableViewCellState2) == MCSwipeTableViewCellState2) {
_completionBlock2 = completionBlock;
_view2 = view;
_color2 = color;
_modeForState2 = mode;
}
if ((state & MCSwipeTableViewCellState3) == MCSwipeTableViewCellState3) {
_completionBlock3 = completionBlock;
_view3 = view;
_color3 = color;
_modeForState3 = mode;
}
if ((state & MCSwipeTableViewCellState4) == MCSwipeTableViewCellState4) {
_completionBlock4 = completionBlock;
_view4 = view;
_color4 = color;
_modeForState4 = mode;
}
}
#pragma mark - Handle Gestures
//滑动手势调用的方法
- (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)gesture {
if (![self shouldDrag] || _isExited) {
//如果不可滑动或者有选中的状态返回
return;
}
UIGestureRecognizerState state = [gesture state];
CGPoint translation = [gesture translationInView:self];
CGPoint velocity = [gesture velocityInView:self];
//计算移动距离的百分比
CGFloat percentage = [self percentageWithOffset:CGRectGetMinX(_contentScreenshotView.frame) relativeToWidth:CGRectGetWidth(self.bounds)];
//计算移动的时间
NSTimeInterval animationDuration = [self animationDurationWithVelocity:velocity];
//判断反弹的方向
_direction = [self directionWithPercentage:percentage];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged) {
_dragging = YES;
//开始移动或者正在移动创建滑动视图
[self setupSwipingView];
//改变滑动视图的中心点时视图移动
CGPoint center = {_contentScreenshotView.center.x + translation.x, _contentScreenshotView.center.y};
_contentScreenshotView.center = center;
[self animateWithOffset:CGRectGetMinX(_contentScreenshotView.frame)];
[gesture setTranslation:CGPointZero inView:self];
// Notifying the delegate that we are dragging with an offset percentage.
if ([_delegate respondsToSelector:@selector(swipeTableViewCell:didSwipeWithPercentage:)]) {
[_delegate swipeTableViewCell:self didSwipeWithPercentage:percentage];
}
}
else if (state == UIGestureRecognizerStateEnded || state == UIGestureRecognizerStateCancelled) {
_dragging = NO;
_activeView = [self viewWithPercentage:percentage];
_currentPercentage = percentage;
MCSwipeTableViewCellState cellState = [self stateWithPercentage:percentage];
MCSwipeTableViewCellMode cellMode = MCSwipeTableViewCellModeNone;
if (cellState == MCSwipeTableViewCellState1 && _modeForState1) {
cellMode = self.modeForState1;
}
else if (cellState == MCSwipeTableViewCellState2 && _modeForState2) {
cellMode = self.modeForState2;
}
else if (cellState == MCSwipeTableViewCellState3 && _modeForState3) {
cellMode = self.modeForState3;
}
else if (cellState == MCSwipeTableViewCellState4 && _modeForState4) {
cellMode = self.modeForState4;
}
if (cellMode == MCSwipeTableViewCellModeExit && _direction != MCSwipeTableViewCellDirectionCenter) {
[self moveWithDuration:animationDuration andDirection:_direction];
}
else {
[self swipeToOriginWithCompletion:^{
[self executeCompletionBlock];
}];
}
// We notify the delegate that we just ended swiping.
if ([_delegate respondsToSelector:@selector(swipeTableViewCellDidEndSwiping:)]) {
[_delegate swipeTableViewCellDidEndSwiping:self];
}
}
}
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer class] == [UIPanGestureRecognizer class]) {
UIPanGestureRecognizer *g = (UIPanGestureRecognizer *)gestureRecognizer;
CGPoint point = [g velocityInView:self];
if (fabsf(point.x) > fabsf(point.y) ) {
if (point.x < 0 && !_modeForState3 && !_modeForState4) {
//如果向左滑动且没有设置触发事件3或4,则返回NO
return NO;
}
if (point.x > 0 && !_modeForState1 && !_modeForState2) {
//如果向右滑动且没有设置触发事件1或2,则返回NO
return NO;
}
// We notify the delegate that we just started dragging
if ([_delegate respondsToSelector:@selector(swipeTableViewCellDidStartSwiping:)]) {
[_delegate swipeTableViewCellDidStartSwiping:self];
}
return YES;
}
}
return NO;
}
#pragma mark - Percentage
- (CGFloat)offsetWithPercentage:(CGFloat)percentage relativeToWidth:(CGFloat)width {
//计算移动的距离
CGFloat offset = percentage * width;
//处理移动距离的边界
if (offset < -width) offset = -width;
else if (offset > width) offset = width;
return offset;
}
- (CGFloat)percentageWithOffset:(CGFloat)offset relativeToWidth:(CGFloat)width {
//计算移动距离的百分比
CGFloat percentage = offset / width;
//处理百分比的边界
if (percentage < -1.0) percentage = -1.0;
else if (percentage > 1.0) percentage = 1.0;
return percentage;
}
- (NSTimeInterval)animationDurationWithVelocity:(CGPoint)velocity {
CGFloat width = CGRectGetWidth(self.bounds);
NSTimeInterval animationDurationDiff = kMCDurationHighLimit - kMCDurationLowLimit;
CGFloat horizontalVelocity = velocity.x;
if (horizontalVelocity < -width) horizontalVelocity = -width;
else if (horizontalVelocity > width) horizontalVelocity = width;
//计算移动的时间
return (kMCDurationHighLimit + kMCDurationLowLimit) - fabs(((horizontalVelocity / width) * animationDurationDiff));
}
- (MCSwipeTableViewCellDirection)directionWithPercentage:(CGFloat)percentage {
//判断反弹的方向
if (percentage < 0) {
return MCSwipeTableViewCellDirectionLeft;
}
else if (percentage > 0) {
return MCSwipeTableViewCellDirectionRight;
}
else {
return MCSwipeTableViewCellDirectionCenter;
}
}
- (UIView *)viewWithPercentage:(CGFloat)percentage {
UIView *view;
//通过计算移动距离的百分比设置状态视图
if (percentage >= 0 && _modeForState1) {
view = _view1;
}
if (percentage >= _secondTrigger && _modeForState2) {
view = _view2;
}
if (percentage < 0 && _modeForState3) {
view = _view3;
}
if (percentage <= -_secondTrigger && _modeForState4) {
view = _view4;
}
return view;
}
- (CGFloat)alphaWithPercentage:(CGFloat)percentage {
CGFloat alpha;
//判断当前视图是否显示
if (percentage >= 0 && percentage < _firstTrigger) {
alpha = percentage / _firstTrigger;
}
else if (percentage < 0 && percentage > -_firstTrigger) {
alpha = fabsf(percentage / _firstTrigger);
}
else {
alpha = 1.0;
}
return alpha;
}
- (UIColor *)colorWithPercentage:(CGFloat)percentage {
UIColor *color;
//根据滑动距离的百分比设置颜色
color = self.defaultColor ? self.defaultColor : [UIColor clearColor];
if (percentage > _firstTrigger && _modeForState1) {
color = _color1;
}
if (percentage > _secondTrigger && _modeForState2) {
color = _color2;
}
if (percentage < -_firstTrigger && _modeForState3) {
color = _color3;
}
if (percentage <= -_secondTrigger && _modeForState4) {
color = _color4;
}
return color;
}
- (MCSwipeTableViewCellState)stateWithPercentage:(CGFloat)percentage {
MCSwipeTableViewCellState state;
//genuine滑动距离的百分比设置触发事件的状态
state = MCSwipeTableViewCellStateNone;
if (percentage >= _firstTrigger && _modeForState1) {
state = MCSwipeTableViewCellState1;
}
if (percentage >= _secondTrigger && _modeForState2) {
state = MCSwipeTableViewCellState2;
}
if (percentage <= -_firstTrigger && _modeForState3) {
state = MCSwipeTableViewCellState3;
}
if (percentage <= -_secondTrigger && _modeForState4) {
state = MCSwipeTableViewCellState4;
}
return state;
}
#pragma mark - Movement
- (void)animateWithOffset:(CGFloat)offset {
//计算移动距离的百分比
CGFloat percentage = [self percentageWithOffset:offset relativeToWidth:CGRectGetWidth(self.bounds)];
//设置状态视图
UIView *view = [self viewWithPercentage:percentage];
// View Position.
if (view) {
[self setViewOfSlidingView:view];
_slidingView.alpha = [self alphaWithPercentage:percentage];
[self slideViewWithPercentage:percentage view:view isDragging:self.shouldAnimateIcons];
}
// Color
UIColor *color = [self colorWithPercentage:percentage];
if (color != nil) {
_colorIndicatorView.backgroundColor = color;
}
}
- (void)slideViewWithPercentage:(CGFloat)percentage view:(UIView *)view isDragging:(BOOL)isDragging {
if (!view) {
return;
}
CGPoint position = CGPointZero;
position.y = CGRectGetHeight(self.bounds) / 2.0;
if (isDragging) {
if (percentage >= 0 && percentage < _firstTrigger) {
position.x = [self offsetWithPercentage:(_firstTrigger / 2) relativeToWidth:CGRectGetWidth(self.bounds)];
}
else if (percentage >= _firstTrigger) {
position.x = [self offsetWithPercentage:percentage - (_firstTrigger / 2) relativeToWidth:CGRectGetWidth(self.bounds)];
}
else if (percentage < 0 && percentage >= -_firstTrigger) {
position.x = CGRectGetWidth(self.bounds) - [self offsetWithPercentage:(_firstTrigger / 2) relativeToWidth:CGRectGetWidth(self.bounds)];
}
else if (percentage < -_firstTrigger) {
position.x = CGRectGetWidth(self.bounds) + [self offsetWithPercentage:percentage + (_firstTrigger / 2) relativeToWidth:CGRectGetWidth(self.bounds)];
}
}
else {
if (_direction == MCSwipeTableViewCellDirectionRight) {
position.x = [self offsetWithPercentage:(_firstTrigger / 2) relativeToWidth:CGRectGetWidth(self.bounds)];
}
else if (_direction == MCSwipeTableViewCellDirectionLeft) {
position.x = CGRectGetWidth(self.bounds) - [self offsetWithPercentage:(_firstTrigger / 2) relativeToWidth:CGRectGetWidth(self.bounds)];
}
else {
return;
}
}
CGSize activeViewSize = view.bounds.size;
CGRect activeViewFrame = CGRectMake(position.x - activeViewSize.width / 2.0,
position.y - activeViewSize.height / 2.0,
activeViewSize.width,
activeViewSize.height);
activeViewFrame = CGRectIntegral(activeViewFrame);
_slidingView.frame = activeViewFrame;
}
- (void)moveWithDuration:(NSTimeInterval)duration andDirection:(MCSwipeTableViewCellDirection)direction {
_isExited = YES;
CGFloat origin;
if (direction == MCSwipeTableViewCellDirectionLeft) {
origin = -CGRectGetWidth(self.bounds);
}
else if (direction == MCSwipeTableViewCellDirectionRight) {
origin = CGRectGetWidth(self.bounds);
}
else {
origin = 0;
}
CGFloat percentage = [self percentageWithOffset:origin relativeToWidth:CGRectGetWidth(self.bounds)];
CGRect frame = _contentScreenshotView.frame;
frame.origin.x = origin;
// Color
UIColor *color = [self colorWithPercentage:_currentPercentage];
if (color) {
[_colorIndicatorView setBackgroundColor:color];
}
[UIView animateWithDuration:duration delay:0 options:(UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction) animations:^{
_contentScreenshotView.frame = frame;
_slidingView.alpha = 0;
[self slideViewWithPercentage:percentage view:_activeView isDragging:self.shouldAnimateIcons];
} completion:^(BOOL finished) {
[self executeCompletionBlock];
}];
}
- (void)swipeToOriginWithCompletion:(void(^)(void))completion {
CGFloat bounceDistance = kMCBounceAmplitude * _currentPercentage;
if ([UIView.class respondsToSelector:@selector(animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)]) {
[UIView animateWithDuration:_animationDuration delay:0.0 usingSpringWithDamping:_damping initialSpringVelocity:_velocity options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect frame = _contentScreenshotView.frame;
frame.origin.x = 0;
_contentScreenshotView.frame = frame;
// Clearing the indicator view
_colorIndicatorView.backgroundColor = self.defaultColor;
_slidingView.alpha = 0;
[self slideViewWithPercentage:0 view:_activeView isDragging:NO];
} completion:^(BOOL finished) {
_isExited = NO;
[self uninstallSwipingView];
if (completion) {
completion();
}
}];
}
else {
[UIView animateWithDuration:kMCBounceDuration1 delay:0 options:(UIViewAnimationOptionCurveEaseOut) animations:^{
CGRect frame = _contentScreenshotView.frame;
frame.origin.x = -bounceDistance;
_contentScreenshotView.frame = frame;
_slidingView.alpha = 0;
[self slideViewWithPercentage:0 view:_activeView isDragging:NO];
// Setting back the color to the default.
_colorIndicatorView.backgroundColor = self.defaultColor;
} completion:^(BOOL finished1) {
[UIView animateWithDuration:kMCBounceDuration2 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
CGRect frame = _contentScreenshotView.frame;
frame.origin.x = 0;
_contentScreenshotView.frame = frame;
// Clearing the indicator view
_colorIndicatorView.backgroundColor = [UIColor clearColor];
} completion:^(BOOL finished2) {
_isExited = NO;
[self uninstallSwipingView];
if (completion) {
completion();
}
}];
}];
}
}
#pragma mark - Utilities
//将传入的View的样子绘成图片并返回
- (UIImage *)imageWithView:(UIView *)view {
CGFloat scale = [[UIScreen mainScreen] scale];
UIGraphicsBeginImageContextWithOptions(view.bounds.size, NO, scale);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
#pragma mark - Completion block
- (void)executeCompletionBlock {
MCSwipeTableViewCellState state = [self stateWithPercentage:_currentPercentage];
MCSwipeTableViewCellMode mode = MCSwipeTableViewCellModeNone;
MCSwipeCompletionBlock completionBlock;
//触发事件后完成block
switch (state) {
case MCSwipeTableViewCellState1: {
mode = self.modeForState1;
completionBlock = _completionBlock1;
} break;
case MCSwipeTableViewCellState2: {
mode = self.modeForState2;
completionBlock = _completionBlock2;
} break;
case MCSwipeTableViewCellState3: {
mode = self.modeForState3;
completionBlock = _completionBlock3;
} break;
case MCSwipeTableViewCellState4: {
mode = self.modeForState4;
completionBlock = _completionBlock4;
} break;
default:
break;
}
if (completionBlock) {
completionBlock(self, state, mode);
}
}
@end