【无限互联】框架学习——MCSwipeTableViewCell

本文介绍了如何使用MCSwipeTableViewCell框架在iOS应用中实现类似Mailbox App的滑动手势效果。该框架适用于UITableViewCell,支持自定义颜色和图标,并且默认提供了滑动删除功能。内容包括MCSwipeTableViewCell的导入、tableView代理设置、单元格的配置和图像视图创建等步骤。

本次学习的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];
    }
}
7.单元格的删除与重新加载
- (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










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值