├── SwipeTableView.gif
├── SwipeTableView
├── Assets.xcassets
│ ├── Contents.json
│ ├── fav.imageset
│ │ ├── fav@2x.png
│ │ └── Contents.json
│ ├── menu.imageset
│ │ ├── menu@2x.png
│ │ └── Contents.json
│ ├── check.imageset
│ │ ├── check@2x.png
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── ViewController.h
├── AppDelegate.h
├── main.m
├── TestModel.h
├── TestModel.m
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── AppDelegate.m
└── ViewController.m
├── SwipeTableView.xcodeproj
├── xcuserdata
│ ├── zhaosongbo.xcuserdatad
│ │ ├── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ │ └── SwipeTableView.xcscheme
│ └── zhao.xcuserdatad
│ │ ├── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── SwipeTableView.xcscheme
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── zhao.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── project.pbxproj
├── README.md
└── Swipe
├── SwipeButton.h
├── SwipeView.h
├── SwipeTableCell.h
├── SwipeButton.m
├── SwipeView.m
└── SwipeTableCell.m
/SwipeTableView.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaoName/SwipeTableView/HEAD/SwipeTableView.gif
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/fav.imageset/fav@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaoName/SwipeTableView/HEAD/SwipeTableView/Assets.xcassets/fav.imageset/fav@2x.png
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/menu.imageset/menu@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaoName/SwipeTableView/HEAD/SwipeTableView/Assets.xcassets/menu.imageset/menu@2x.png
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/check.imageset/check@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaoName/SwipeTableView/HEAD/SwipeTableView/Assets.xcassets/check.imageset/check@2x.png
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/xcuserdata/zhaosongbo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/project.xcworkspace/xcuserdata/zhao.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhaoName/SwipeTableView/HEAD/SwipeTableView.xcodeproj/project.xcworkspace/xcuserdata/zhao.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SwipeTableView/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/SwipeTableView/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/SwipeTableView/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/fav.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "fav@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/menu.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "menu@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/check.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "check@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwipeTableView
2 |
3 | 博客:http://blog.csdn.net/qq244596/article/details/52037253
4 |
5 | 本文参考:https://github.com/MortimerGoro/MGSwipeTableCell
6 |
7 | 自定义右滑、左滑tableView时显示的按钮,可以只显示文字、只显示图片或文字图片同时显示。
8 |
9 | 使用起来也很简单,将Swipe文件夹拖入你的工程中,实现SwipeTableViewDelegate的代理方法,返回左滑或右滑时显示的按钮和按钮的样式。
10 |
11 | 创建左滑、右滑按钮只需传入文字、图片,按钮会根据文字和图片的大小自适应宽高。swipeView上按钮的位置和系统自带UITableViewRowAction一样,右滑时返回数组的第一个元素在swipeView的最右侧显示,最后一个元素在最左侧显示;左滑时swipeView上按钮的顺序和数组一致。
12 |
13 | 效果如下
14 |
15 | 
16 |
--------------------------------------------------------------------------------
/SwipeTableView/TestModel.h:
--------------------------------------------------------------------------------
1 | //
2 | // TestModel.h
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/11/14.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SwipeView.h"
11 | #import "SwipeTableCell.h"
12 |
13 | @interface TestModel : NSObject
14 |
15 | @property (nonatomic, assign) SwipeTableCellStyle cellStyle;
16 | @property (nonatomic, assign) SwipeViewTransfromMode transformMode;
17 | @property (nonatomic, assign) BOOL isRefreshButton;
18 | @property (nonatomic, strong) NSString *data;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/xcuserdata/zhao.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/xcuserdata/zhao.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwipeTableView.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | FECCB01A1D5C649D002FDD6C
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/SwipeTableView/TestModel.m:
--------------------------------------------------------------------------------
1 | //
2 | // TestModel.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/11/14.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import "TestModel.h"
10 |
11 | @implementation TestModel
12 |
13 | @synthesize transformMode = _transformMode;
14 | @synthesize cellStyle = _cellStyle;
15 | @synthesize isRefreshButton = _isRefreshButton;
16 |
17 |
18 | - (void)setTransformMode:(SwipeViewTransfromMode)transformMode
19 | {
20 | _transformMode = transformMode;
21 | }
22 |
23 | - (SwipeViewTransfromMode)transformMode
24 | {
25 | return _transformMode;
26 | }
27 |
28 |
29 | - (void)setCellStyle:(SwipeTableCellStyle)cellStyle
30 | {
31 | _cellStyle = cellStyle;
32 | }
33 |
34 | - (SwipeTableCellStyle)cellStyle
35 | {
36 | return _cellStyle;
37 | }
38 |
39 |
40 | - (void)setIsRefreshButton:(BOOL)isRefreshButton
41 | {
42 | _isRefreshButton = isRefreshButton;
43 | }
44 |
45 | - (BOOL)isRefreshButton
46 | {
47 | return _isRefreshButton;
48 | }
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/SwipeTableView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Swipe/SwipeButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeButton.h
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef void(^TouchSwipeButtonBlock)(void);
12 |
13 | @interface SwipeButton : UIButton
14 |
15 | @property (nonatomic, strong) TouchSwipeButtonBlock touchBlock;
16 |
17 | /**
18 | * 创建左滑或右滑时的button, button只有title没有Image
19 | *
20 | * @param title button的标题
21 | * @param font button的字体大小 默认为15
22 | * @param textColor button的字体颜色 默认黑色
23 | * @param backgroundColor button的背景颜色 默认白色
24 | */
25 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title backgroundColor:(UIColor *)backgroundColor touchBlock:(TouchSwipeButtonBlock)block;
26 |
27 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title font:(CGFloat)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor touchBlock:(TouchSwipeButtonBlock)block;
28 |
29 |
30 | /**
31 | * 创建左滑或右滑时的button, button只有Image没有title
32 | */
33 | + (SwipeButton *)createSwipeButtonWithImage:(UIImage *)image backgroundColor:(UIColor *)color touchBlock:(TouchSwipeButtonBlock)block;
34 |
35 | /**
36 | * 创建左滑或右滑时的button,文字图片同时存在,且image在上 title在下
37 | */
38 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title backgroundColor:(UIColor *)backgroundColor image:(UIImage *)image touchBlock:(TouchSwipeButtonBlock)block;
39 |
40 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title font:(CGFloat)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor image:(UIImage *)image touchBlock:(TouchSwipeButtonBlock)block;
41 |
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/SwipeTableView/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "8.0",
8 | "subtype" : "736h",
9 | "scale" : "3x"
10 | },
11 | {
12 | "orientation" : "landscape",
13 | "idiom" : "iphone",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "8.0",
16 | "subtype" : "736h",
17 | "scale" : "3x"
18 | },
19 | {
20 | "orientation" : "portrait",
21 | "idiom" : "iphone",
22 | "extent" : "full-screen",
23 | "minimum-system-version" : "8.0",
24 | "subtype" : "667h",
25 | "scale" : "2x"
26 | },
27 | {
28 | "orientation" : "portrait",
29 | "idiom" : "iphone",
30 | "extent" : "full-screen",
31 | "minimum-system-version" : "7.0",
32 | "scale" : "2x"
33 | },
34 | {
35 | "orientation" : "portrait",
36 | "idiom" : "iphone",
37 | "extent" : "full-screen",
38 | "minimum-system-version" : "7.0",
39 | "subtype" : "retina4",
40 | "scale" : "2x"
41 | },
42 | {
43 | "orientation" : "portrait",
44 | "idiom" : "iphone",
45 | "extent" : "full-screen",
46 | "scale" : "1x"
47 | },
48 | {
49 | "orientation" : "portrait",
50 | "idiom" : "iphone",
51 | "extent" : "full-screen",
52 | "scale" : "2x"
53 | },
54 | {
55 | "orientation" : "portrait",
56 | "idiom" : "iphone",
57 | "extent" : "full-screen",
58 | "subtype" : "retina4",
59 | "scale" : "2x"
60 | }
61 | ],
62 | "info" : {
63 | "version" : 1,
64 | "author" : "xcode"
65 | }
66 | }
--------------------------------------------------------------------------------
/SwipeTableView/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Swipe/SwipeView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeView.h
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/29.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef NS_ENUM(NSInteger, MGSwipeEasingFunction) {
12 | MGSwipeEasingFunctionLinear = 0,
13 | MGSwipeEasingFunctionQuadIn,
14 | MGSwipeEasingFunctionQuadOut,
15 | MGSwipeEasingFunctionQuadInOut,
16 | MGSwipeEasingFunctionCubicIn,
17 | MGSwipeEasingFunctionCubicOut,
18 | MGSwipeEasingFunctionCubicInOut,
19 | MGSwipeEasingFunctionBounceIn,
20 | MGSwipeEasingFunctionBounceOut,
21 | MGSwipeEasingFunctionBounceInOut
22 | };
23 |
24 | typedef NS_ENUM(NSUInteger, SwipeViewTransfromMode)
25 | {
26 | SwipeViewTransfromModeDefault = 0, /**< 默认效果,拖拽*/
27 | SwipeViewTransfromModeStatic, /**< 静态效果*/
28 | SwipeViewTransfromModeBorder, /**< 渐出效果*/
29 | SwipeViewTransfromMode3D, /**< 3D效果*/
30 | };
31 |
32 |
33 | @interface SwipeView : UIView
34 |
35 | @property (nonatomic, assign) CGFloat from;
36 | @property (nonatomic, assign) CGFloat to;
37 | @property (nonatomic, assign) CFTimeInterval start;
38 | @property (nonatomic, assign) CGFloat duration; /**<动画持续时间 默认0.3*/
39 | @property (nonatomic, assign) MGSwipeEasingFunction easingFunction; /**< 手势动画执行节奏*/
40 | @property (nonatomic, assign) SwipeViewTransfromMode mode;/**< swipeView的弹出效果*/
41 |
42 | /**
43 | * 初始化swipeView,添加滑动按钮
44 | */
45 | - (instancetype)initWithButtons:(NSArray *)buttos fromRight:(BOOL)fromRight cellHeght:(CGFloat)cellHeight edge:(UIEdgeInsets)edge;
46 |
47 | /**
48 | * 滑动手势滑动的距离超过swipeView的一半时,会自动显示或隐藏swipeView
49 | */
50 | - (CGFloat)value:(CGFloat)elapsed duration:(CGFloat)duration from:(CGFloat)from to:(CGFloat)to;
51 |
52 | /**
53 | * swipeView的弹出、隐藏动画
54 | *
55 | * @param fromRight 是否是右滑
56 | * @param t 动画控制量
57 | * @param cellHeight cell的高度
58 | */
59 | - (void)swipeViewAnimationFromRight:(BOOL)fromRight effect:(CGFloat)t cellHeight:(CGFloat)cellHeight;
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/SwipeTableView/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/SwipeTableView/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Swipe/SwipeTableCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeTableCell.h
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "SwipeButton.h"
11 | #import "SwipeView.h"
12 |
13 | typedef NS_ENUM(NSUInteger, SwipeTableCellStyle)
14 | {
15 | SwipeTableCellStyleRightToLeft = 0, /**< 右滑*/
16 | SwipeTableCellStyleLeftToRight , /**< 左滑*/
17 | SwipeTableCellStyleBoth, /**< 左滑、右滑都有*/
18 | };
19 |
20 | @class SwipeTableCell;
21 | @protocol SwipeTableViewCellDelegate
22 |
23 | @required
24 | /**
25 | * 设置cell的滑动按钮的样式 (左滑、右滑、左滑右滑都有)
26 | *
27 | * @param indexPath cell的位置
28 | */
29 | - (SwipeTableCellStyle)tableView:(UITableView *)tableView styleOfSwipeButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
30 |
31 | /**
32 | * 左滑cell时显示的button
33 | *
34 | * @param indexPath cell的位置
35 | */
36 | - (NSArray *)tableView:(UITableView *)tableView leftSwipeButtonsAtIndexPath:(NSIndexPath *)indexPath;
37 |
38 | /**
39 | * 右滑cell时显示的button
40 | *
41 | * @param indexPath cell的位置
42 | */
43 | - (NSArray *)tableView:(UITableView *)tableView rightSwipeButtonsAtIndexPath:(NSIndexPath *)indexPath;
44 |
45 | @optional
46 | /**
47 | * 当滑动手势结束后,点击cell是否隐藏swipeView,即cell自动回复到最初状态。默认YES
48 | */
49 | - (BOOL)tableView:(UITableView *)tableView hiddenSwipeViewWhenTapCellAtIndexPath:(NSIndexPath *)indexPath;
50 |
51 | /**
52 | * 点击按钮隐藏SwipeView 默认YES
53 | *
54 | * @param cell 按钮所在的cell
55 | *
56 | * @return 是否隐藏
57 | */
58 | - (BOOL)hideSwipeViewWhenClickSwipeButtonAtCell:(SwipeTableCell *)cell;
59 |
60 | /**
61 | * 设置swipeView的弹出样式
62 | */
63 | - (SwipeViewTransfromMode)tableView:(UITableView *)tableView swipeViewTransformModeAtIndexPath:(NSIndexPath *)indexPath;
64 |
65 | /**
66 | * 设置swipeButton 距SwipeTableCell上左下右的间距
67 | *
68 | * @warn 值要>0 否则可能导致显示不全
69 | */
70 | - (UIEdgeInsets)tableView:(UITableView *)tableView swipeButtonEdgeAtIndexPath:(NSIndexPath *)indexPath;
71 |
72 | @end
73 |
74 |
75 | @class SwipeTableViewDelegate;
76 | @interface SwipeTableCell : UITableViewCell
77 |
78 | @property (nonatomic, weak) id swipeDelegate;
79 | /** swipeButton下的背景色 默认透明色*/
80 | @property (nonatomic, strong) UIColor *swipeOverlayViewBackgroundColor;
81 | /** 当结束滑动手势时,显示或隐藏SwipeView的临界值 范围:0-1,默认0.5*/
82 | @property (nonatomic, assign) CGFloat swipeThreshold;
83 |
84 | /** 是否允许多个cell同时滑动 默认NO*/
85 | @property (nonatomic, assign) BOOL isAllowMultipleSwipe;
86 | /** 滚动TableView时是否隐藏swipeView 默认YES*/
87 | @property (nonatomic, assign, readonly) BOOL hideSwipeViewWhenScrollTableView;
88 | /** 点击按钮隐藏SwipeView 默认YES*/
89 | @property (nonatomic, assign) BOOL hideSwipeViewWhenClickSwipeButton;
90 |
91 |
92 | /** 是否允许拉伸 默认NO(模仿系统邮件自带拉伸删除)*/
93 | @property (nonatomic, assign) BOOL isAllowExpand;
94 | /** 拉伸按钮的下标*/
95 | @property (nonatomic, assign) NSInteger expandSwipeBtnAtIndex;
96 | /** 拉伸临界值 1-2,默认1.5*/
97 | @property (nonatomic, assign) CGFloat expandThreshold;
98 |
99 |
100 | /**
101 | * 隐藏滑动按钮 即将cell恢复原状
102 | *
103 | * @param isAnimation 是否隐藏
104 | */
105 | - (void)hiddenSwipeAnimationAtCell:(BOOL)isAnimation;
106 |
107 | /**
108 | * 更改滑动按钮的内容 如置顶变成取消置顶
109 | */
110 | - (void)refreshButtonContent;
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/xcuserdata/zhao.xcuserdatad/xcschemes/SwipeTableView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/xcuserdata/zhaosongbo.xcuserdatad/xcschemes/SwipeTableView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Swipe/SwipeButton.m:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeButton.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import "SwipeButton.h"
10 |
11 | #define NULL_STRING(string) [string isEqualToString:@""] || !string
12 |
13 | @implementation SwipeButton
14 |
15 | //只有title
16 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title backgroundColor:(UIColor *)backgroundColor touchBlock:(TouchSwipeButtonBlock)block
17 | {
18 | return [self createSwipeButtonWithTitle:title font:15 textColor:[UIColor blackColor] backgroundColor:backgroundColor touchBlock:block];
19 | }
20 |
21 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title font:(CGFloat)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor touchBlock:(TouchSwipeButtonBlock)block
22 | {
23 | return [self createSwipeButtonWithTitle:title font:font textColor:textColor backgroundColor:backgroundColor image:nil touchBlock:block];
24 | }
25 |
26 |
27 | //只有图片
28 | + (SwipeButton *)createSwipeButtonWithImage:(UIImage *)image backgroundColor:(UIColor *)color touchBlock:(TouchSwipeButtonBlock)block
29 | {
30 | return [self createSwipeButtonWithTitle:nil font:15 textColor:[UIColor blackColor] backgroundColor:color image:image touchBlock:block];
31 | }
32 |
33 | //图片、文字都有,且图片在上 文字在下
34 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title backgroundColor:(UIColor *)backgroundColor image:(UIImage *)image touchBlock:(TouchSwipeButtonBlock)block
35 | {
36 | return [self createSwipeButtonWithTitle:title font:15 textColor:[UIColor blackColor] backgroundColor:backgroundColor image:image touchBlock:block];
37 | }
38 |
39 | + (SwipeButton *)createSwipeButtonWithTitle:(NSString *)title font:(CGFloat)font textColor:(UIColor *)textColor backgroundColor:(UIColor *)backgroundColor image:(UIImage *)image touchBlock:(TouchSwipeButtonBlock)block
40 | {
41 | SwipeButton *button = [self buttonWithType:UIButtonTypeCustom];
42 |
43 | [button setTitle:title forState:UIControlStateNormal];
44 | button.titleLabel.font = [UIFont systemFontOfSize:font];
45 | [button setTitleColor:textColor forState:UIControlStateNormal];
46 | button.backgroundColor = backgroundColor;
47 | [button setImage:image forState:UIControlStateNormal];
48 | button.touchBlock = block;
49 |
50 | // 算出文字的size
51 | CGSize titleSize = [title boundingRectWithSize:CGSizeMake(MAXFLOAT, button.titleLabel.frame.size.height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:font]} context:nil].size;
52 | // button的宽度去文字和图片两个中的最大宽度 其它值将在SwipeView中设置
53 | button.frame = CGRectMake(0, 0, MAX(titleSize.width+10, image.size.width+10), 0);
54 | if(!NULL_STRING(title) && !image)
55 | {
56 | button.titleEdgeInsets = UIEdgeInsetsMake(image.size.height, -image.size.width, 0, 0);
57 | button.imageEdgeInsets = UIEdgeInsetsMake(-titleSize.height, 0.5*titleSize.width, 0.5*titleSize.height, 0);
58 | }
59 |
60 | return button;
61 | }
62 |
63 | /**
64 | * 防止文字太长或图片太大 导致图片或文字的位置不在中间
65 | */
66 | - (void)layoutSubviews
67 | {
68 | [super layoutSubviews];
69 |
70 | if(self.titleLabel.text && self.imageView.image)
71 | {
72 | CGFloat marginH = (self.frame.size.height - self.imageView.frame.size.height - self.titleLabel.frame.size.height)/3;
73 |
74 | //图片
75 | CGPoint imageCenter = self.imageView.center;
76 | imageCenter.x = self.frame.size.width/2;
77 | imageCenter.y = self.imageView.frame.size.height/2 + marginH;
78 | self.imageView.center = imageCenter;
79 | //文字
80 | CGRect newFrame = self.titleLabel.frame;
81 | newFrame.origin.x = 0;
82 | newFrame.origin.y = self.frame.size.height - newFrame.size.height - marginH;
83 | newFrame.size.width = self.frame.size.width;
84 | self.titleLabel.frame = newFrame;
85 | self.titleLabel.textAlignment = NSTextAlignmentCenter;
86 | }
87 | }
88 |
89 | @end
90 |
--------------------------------------------------------------------------------
/SwipeTableView/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "SwipeTableCell.h"
11 | #import "TestModel.h"
12 |
13 | #define WIDTH [UIScreen mainScreen].bounds.size.width
14 | #define HEIGHT [UIScreen mainScreen].bounds.size.height
15 |
16 | @interface ViewController ()
17 |
18 | @property (nonatomic, strong) NSMutableArray *dataArray;
19 | @property (nonatomic, strong) UITableView *tableView;
20 |
21 | @end
22 |
23 | @implementation ViewController
24 |
25 | - (void)viewDidLoad {
26 | [super viewDidLoad];
27 |
28 | self.tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, WIDTH, HEIGHT) style:UITableViewStylePlain];
29 | self.tableView.delegate = self;
30 | self.tableView.dataSource = self;
31 | self.tableView.showsVerticalScrollIndicator= NO;
32 | [self.view addSubview:self.tableView];
33 |
34 | for(int i=0; i<20; i++)
35 | {
36 | TestModel *teModel = [[TestModel alloc] init];
37 | teModel.isRefreshButton = YES;
38 | teModel.data = [NSString stringWithFormat:@"测试数据%10d", i+100];
39 | [self.dataArray addObject:teModel];
40 | }
41 | }
42 |
43 | #pragma mark -- UITableViewDelegate
44 |
45 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
46 | {
47 | return self.dataArray.count;
48 | }
49 |
50 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
51 | {
52 | return 64;
53 | }
54 |
55 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
56 | {
57 | SwipeTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CELL"];
58 | if(cell == nil)
59 | {
60 | cell = [[SwipeTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CELL"];
61 | }
62 |
63 | cell.swipeDelegate = self;
64 | if (indexPath.row == 0) cell.swipeOverlayViewBackgroundColor = [UIColor grayColor];
65 | cell.selectionStyle = UITableViewCellSelectionStyleDefault;
66 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
67 | TestModel *model = self.dataArray[indexPath.row];
68 | cell.textLabel.text = model.data;
69 | cell.textLabel.font = [UIFont systemFontOfSize:16];
70 |
71 | return cell;
72 | }
73 |
74 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
75 | {
76 | NSLog(@"点击了section:%lu row:%lu", indexPath.section, indexPath.row);
77 | }
78 |
79 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
80 | {
81 | return 0.1;
82 | }
83 |
84 | #pragma mark -- SwipeTableViewDelegate
85 |
86 | // cell的滑动样式
87 | - (SwipeTableCellStyle)tableView:(UITableView *)tableView styleOfSwipeButtonForRowAtIndexPath:(NSIndexPath *)indexPath
88 | {
89 | if(indexPath.row == 0){
90 | return SwipeTableCellStyleBoth;
91 | }
92 | else if(indexPath.row % 2 == 0){
93 | return SwipeTableCellStyleRightToLeft;
94 | }
95 | else{
96 | return SwipeTableCellStyleLeftToRight;
97 | }
98 |
99 | //return [self.dataArray[indexPath.row] cellStyle];
100 | }
101 |
102 | // 左滑buttons
103 | - (NSArray *)tableView:(UITableView *)tableView leftSwipeButtonsAtIndexPath:(NSIndexPath *)indexPath
104 | {
105 | SwipeButton *checkBtn = [SwipeButton createSwipeButtonWithTitle:@"删除峰删除" font:16 textColor:[UIColor blackColor] backgroundColor:[UIColor redColor] image:[UIImage imageNamed:@"check"] touchBlock:^{
106 |
107 | NSLog(@"点击了check按钮");
108 | }];
109 | SwipeButton *menuBtn = [SwipeButton createSwipeButtonWithImage:[UIImage imageNamed:@"menu"] backgroundColor:[UIColor blueColor] touchBlock:^{
110 |
111 | NSLog(@"点击了menu按钮");
112 | }];
113 | return @[checkBtn, menuBtn];
114 | }
115 |
116 | // 右滑buttons
117 | - (NSArray *)tableView:(UITableView *)tableView rightSwipeButtonsAtIndexPath:(NSIndexPath *)indexPath
118 | {
119 | __block SwipeTableCell * cell = [tableView cellForRowAtIndexPath:indexPath];
120 | TestModel *model = self.dataArray[indexPath.row];
121 | // 删除操作
122 | SwipeButton *checkBtn = [SwipeButton createSwipeButtonWithTitle:@"删除峰删除" font:16 textColor:[UIColor blackColor] backgroundColor:[UIColor redColor] image:[UIImage imageNamed:@"check"] touchBlock:^{
123 |
124 | //NSLog(@"%lu, %lu", indexPath.section, indexPath.row);
125 | [self.dataArray removeObjectAtIndex:indexPath.row];
126 | [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];
127 | NSLog(@"点击了check按钮");
128 | }];
129 |
130 | SwipeButton *favBtn = [SwipeButton createSwipeButtonWithTitle:model.isRefreshButton ? @"置顶" : @"取消置顶" font:16 textColor:[UIColor blackColor] backgroundColor:[UIColor greenColor] image:model.isRefreshButton ? [UIImage imageNamed:@"fav"]:[UIImage imageNamed:@"check"] touchBlock:^{
131 |
132 | model.isRefreshButton = !model.isRefreshButton;
133 | [cell refreshButtonContent];
134 |
135 | NSLog(@"点击了fav按钮");
136 | }];
137 |
138 | SwipeButton *menuBtn = [SwipeButton createSwipeButtonWithImage:[UIImage imageNamed:@"menu"] backgroundColor:[UIColor blueColor] touchBlock:^{
139 |
140 | NSLog(@"点击了menu按钮");
141 | }];
142 |
143 | if(indexPath.row == 0){
144 | return @[checkBtn, favBtn, menuBtn];
145 | }
146 | else if(indexPath.row == 2){
147 | return @[favBtn, menuBtn];
148 | }
149 | else{
150 | return @[checkBtn, menuBtn];
151 | }
152 | }
153 |
154 | // swipeView的弹出样式
155 | - (SwipeViewTransfromMode)tableView:(UITableView *)tableView swipeViewTransformModeAtIndexPath:(NSIndexPath *)indexPath
156 | {
157 | if(indexPath.row == 0)
158 | {
159 | return SwipeViewTransfromModeStatic;
160 | }
161 | else if(indexPath.row < 3){
162 | return SwipeViewTransfromModeBorder;
163 | }
164 | else if (indexPath.row > 7){
165 | return SwipeViewTransfromMode3D;
166 | }
167 | return SwipeViewTransfromModeDefault;
168 |
169 | //return [self.dataArray[indexPath.row] transformMode];
170 | }
171 |
172 | // swipeButton 距上左下右的间距 注意不能刚给负值
173 | - (UIEdgeInsets)tableView:(UITableView *)tableView swipeButtonEdgeAtIndexPath:(NSIndexPath *)indexPath
174 | {
175 | if (indexPath.row == 0) {
176 | return UIEdgeInsetsMake(5, 5, 5, 5);
177 | }
178 | return UIEdgeInsetsZero;
179 | }
180 |
181 | #pragma mark -- getter
182 |
183 | - (NSMutableArray *)dataArray
184 | {
185 | if(!_dataArray)
186 | {
187 | _dataArray = [[NSMutableArray alloc] init];
188 | }
189 | return _dataArray;
190 | }
191 |
192 | @end
193 |
--------------------------------------------------------------------------------
/Swipe/SwipeView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeView.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/29.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import "SwipeView.h"
10 | #import "SwipeButton.h"
11 | #import "SwipeTableCell.h"
12 |
13 | static inline CGFloat mgEaseLinear(CGFloat t, CGFloat b, CGFloat c) {
14 | return c*t + b;
15 | }
16 |
17 | static inline CGFloat mgEaseInQuad(CGFloat t, CGFloat b, CGFloat c) {
18 | return c*t*t + b;
19 | }
20 | static inline CGFloat mgEaseOutQuad(CGFloat t, CGFloat b, CGFloat c) {
21 | return -c*t*(t-2) + b;
22 | }
23 | static inline CGFloat mgEaseInOutQuad(CGFloat t, CGFloat b, CGFloat c) {
24 | if ((t*=2) < 1) return c/2*t*t + b;
25 | --t;
26 | return -c/2 * (t*(t-2) - 1) + b;
27 | }
28 | static inline CGFloat mgEaseInCubic(CGFloat t, CGFloat b, CGFloat c) {
29 | return c*t*t*t + b;
30 | }
31 | static inline CGFloat mgEaseOutCubic(CGFloat t, CGFloat b, CGFloat c) {
32 | --t;
33 | return c*(t*t*t + 1) + b;
34 | }
35 | static inline CGFloat mgEaseInOutCubic(CGFloat t, CGFloat b, CGFloat c) {
36 | if ((t*=2) < 1) return c/2*t*t*t + b;
37 | t-=2;
38 | return c/2*(t*t*t + 2) + b;
39 | }
40 | static inline CGFloat mgEaseOutBounce(CGFloat t, CGFloat b, CGFloat c) {
41 | if (t < (1/2.75)) {
42 | return c*(7.5625*t*t) + b;
43 | } else if (t < (2/2.75)) {
44 | t-=(1.5/2.75);
45 | return c*(7.5625*t*t + .75) + b;
46 | } else if (t < (2.5/2.75)) {
47 | t-=(2.25/2.75);
48 | return c*(7.5625*t*t + .9375) + b;
49 | } else {
50 | t-=(2.625/2.75);
51 | return c*(7.5625*t*t + .984375) + b;
52 | }
53 | };
54 | static inline CGFloat mgEaseInBounce(CGFloat t, CGFloat b, CGFloat c) {
55 | return c - mgEaseOutBounce (1.0 -t, 0, c) + b;
56 | };
57 |
58 | static inline CGFloat mgEaseInOutBounce(CGFloat t, CGFloat b, CGFloat c) {
59 | if (t < 0.5) return mgEaseInBounce (t*2, 0, c) * .5 + b;
60 | return mgEaseOutBounce (1.0 - t*2, 0, c) * .5 + c*.5 + b;
61 | };
62 |
63 |
64 |
65 | @interface SwipeView ()
66 |
67 | @property (nonatomic, strong) UIView *containView; /**< 装swipeButton的容器*/
68 | @property (nonatomic, strong) NSArray *buttonArray; /**< 重新排序后的buttons*/
69 | @property (nonatomic, assign) UIEdgeInsets btnEdge; /**< swipeBtn间距*/
70 |
71 | @end
72 |
73 | @implementation SwipeView
74 |
75 | - (instancetype)initWithButtons:(NSArray *)buttos fromRight:(BOOL)fromRight cellHeght:(CGFloat)cellHeight edge:(UIEdgeInsets)edge
76 | {
77 | CGFloat containerWidth = 0;
78 | CGFloat horizontalSpace = ABS(edge.left) + ABS(edge.right);
79 | CGFloat verticalSpace = ABS(edge.top) + ABS(edge.bottom);
80 | // 计算buttons的总宽度
81 | for(SwipeButton *button in buttos){
82 | containerWidth += MAX(button.frame.size.width, cellHeight - verticalSpace);
83 | }
84 | // 加上左右间距
85 | containerWidth += horizontalSpace;
86 |
87 | if([super initWithFrame:CGRectMake(0, 0, containerWidth, cellHeight - verticalSpace)])
88 | {
89 | self.btnEdge = edge;
90 | self.duration = 0.3;
91 | self.easingFunction = MGSwipeEasingFunctionCubicOut;
92 | self.containView.frame = CGRectMake(0, ABS(edge.top), containerWidth, cellHeight - verticalSpace);
93 |
94 | // 若是右滑 则倒序。即将数组的最后一个元素放在swipeView的最后
95 | self.buttonArray = fromRight ? [[buttos reverseObjectEnumerator] allObjects] : buttos;
96 | [self addSubview:self.containView];
97 |
98 | CGFloat offset = ABS(edge.left);
99 | for(SwipeButton *button in self.buttonArray)
100 | {
101 | button.frame = CGRectMake(offset, 0, MAX(button.frame.size.width, cellHeight - verticalSpace), cellHeight - verticalSpace);
102 | offset += button.frame.size.width;
103 | // 防止重用问题,移除点击事件
104 | [button removeTarget:self action:@selector(touchSwipeButton:) forControlEvents:UIControlEventTouchUpInside];
105 | [button addTarget:self action:@selector(touchSwipeButton:) forControlEvents:UIControlEventTouchUpInside];
106 | // 直接用addSubview会覆盖左滑的动画效果
107 | [self.containView insertSubview:button atIndex:fromRight ? self.containView.subviews.count : 0];
108 | }
109 | }
110 | return self;
111 | }
112 |
113 | /**
114 | * 点击滑动按钮的响应事件
115 | */
116 | - (void)touchSwipeButton:(SwipeButton *)btn
117 | {
118 | // 点击按钮隐藏滑动按钮,即将cell恢复原状
119 | [self hideSwipeView];
120 | // 点击按钮的回调事件
121 | btn.touchBlock();
122 | }
123 |
124 | /**
125 | * 点击SwipeButton隐藏SwipeView,即将cell恢复原状
126 | */
127 | - (void)hideSwipeView
128 | {
129 | SwipeTableCell *cell = nil;
130 | UIView *view = self.superview;
131 | while (view != nil)
132 | {
133 | if([view isKindOfClass:[SwipeTableCell class]])
134 | {
135 | cell = (SwipeTableCell *)view;
136 | break;
137 | }
138 | view = view.superview;
139 | }
140 | if(cell.swipeDelegate && [cell.swipeDelegate respondsToSelector:@selector(hideSwipeViewWhenClickSwipeButtonAtCell:)])
141 | {
142 | cell.hideSwipeViewWhenClickSwipeButton = [cell.swipeDelegate hideSwipeViewWhenClickSwipeButtonAtCell:cell];
143 | }
144 | [cell hiddenSwipeAnimationAtCell:cell.hideSwipeViewWhenClickSwipeButton];
145 | }
146 |
147 | #pragma mark -- 动画效果
148 |
149 | // 手势动画效果
150 | -(CGFloat)value:(CGFloat)elapsed duration:(CGFloat)duration from:(CGFloat)from to:(CGFloat)to
151 | {
152 | CGFloat t = MIN(elapsed/duration, 1.0f);
153 | if (t == 1.0) {
154 | return to;
155 | }
156 | CGFloat (*easingFunction)(CGFloat t, CGFloat b, CGFloat c) = 0;
157 | switch (_easingFunction) {
158 | case MGSwipeEasingFunctionLinear: easingFunction = mgEaseLinear; break;
159 | case MGSwipeEasingFunctionQuadIn: easingFunction = mgEaseInQuad; break;
160 | case MGSwipeEasingFunctionQuadOut: easingFunction = mgEaseOutQuad; break;
161 | case MGSwipeEasingFunctionQuadInOut: easingFunction = mgEaseInOutQuad; break;
162 | case MGSwipeEasingFunctionCubicIn: easingFunction = mgEaseInCubic; break;
163 | default:
164 | case MGSwipeEasingFunctionCubicOut: easingFunction = mgEaseOutCubic;break;
165 | case MGSwipeEasingFunctionCubicInOut: easingFunction = mgEaseInOutCubic;break;
166 | case MGSwipeEasingFunctionBounceIn: easingFunction = mgEaseInBounce;break;
167 | case MGSwipeEasingFunctionBounceOut: easingFunction = mgEaseOutBounce;break;
168 | case MGSwipeEasingFunctionBounceInOut: easingFunction = mgEaseInOutBounce;break;
169 | }
170 | return (*easingFunction)(t, from, to - from);
171 | }
172 |
173 | // swipeView的弹出动画效果
174 | - (void)swipeViewAnimationFromRight:(BOOL)fromRight effect:(CGFloat)t cellHeight:(CGFloat)cellHeight
175 | {
176 | CGFloat verticalSpace = self.btnEdge.top + self.btnEdge.bottom;
177 | switch (self.mode)
178 | {
179 | case SwipeViewTransfromModeDefault:break; // 默认的效果
180 | case SwipeViewTransfromModeStatic:
181 | {
182 | const CGFloat dx = self.bounds.size.width * (1.0 - t);
183 | CGFloat offsetX = ABS(self.btnEdge.left);
184 |
185 | for (UIView *button in self.buttonArray) {
186 | CGRect frame = button.frame;
187 | frame.origin.x = offsetX + (fromRight ? -dx : dx);
188 | button.frame = frame;
189 | offsetX += frame.size.width;
190 | }
191 | }
192 | break;
193 | case SwipeViewTransfromModeBorder: // 渐出
194 | {
195 | CGFloat selfWidth = self.bounds.size.width;
196 | CGFloat offsetX = ABS(self.btnEdge.left);
197 |
198 | for (SwipeButton *button in self.buttonArray)
199 | {
200 | CGRect frame = button.frame;
201 | CGFloat x = fromRight ? offsetX * t : (selfWidth - MAX(frame.size.width, cellHeight - verticalSpace) - offsetX) * (1.0 - t) + offsetX;
202 | button.frame = CGRectMake(x, 0, MAX(frame.size.width, cellHeight - verticalSpace), cellHeight - verticalSpace);
203 | offsetX += MAX(frame.size.width, cellHeight - verticalSpace);
204 | }
205 | }
206 | break;
207 | case SwipeViewTransfromMode3D: // 3D
208 | {
209 | const CGFloat invert = fromRight ? -1.0 : 1.0;
210 | const CGFloat angle = M_PI_2 * (1.0 - t) * invert;
211 | CATransform3D transform = CATransform3DIdentity;
212 | transform.m34 = -1.0/400.0f;
213 | const CGFloat dx = -_containView.frame.size.width * 0.5 * invert;
214 | const CGFloat offset = dx * 2 * (1.0-t);
215 | transform = CATransform3DTranslate(transform, dx - offset, 0, 0);
216 | transform = CATransform3DRotate(transform, angle, 0.0, 1.0, 0.0);
217 | transform = CATransform3DTranslate(transform, -dx, 0, 0);
218 | self.containView.layer.transform = transform;
219 | }
220 | break;
221 | }
222 | }
223 |
224 |
225 | - (void)removeAllSubViewsAtView:(UIView *)view
226 | {
227 | while (view.subviews.count) {
228 | [[view.subviews lastObject] removeFromSuperview];
229 | }
230 | }
231 |
232 | #pragma mark -- 懒加载
233 |
234 | - (UIView *)containView
235 | {
236 | if(!_containView)
237 | {
238 | _containView = [[UIView alloc] initWithFrame:self.bounds];
239 | _containView.backgroundColor = [UIColor clearColor];
240 | _containView.clipsToBounds = YES;
241 | }
242 | return _containView;
243 | }
244 |
245 | - (NSArray *)buttonArray
246 | {
247 | if(!_buttonArray)
248 | {
249 | _buttonArray = [NSArray array];
250 | }
251 | return _buttonArray;
252 | }
253 |
254 | @end
255 |
--------------------------------------------------------------------------------
/SwipeTableView.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | FEBCD5FA1DD957AB00F55318 /* TestModel.m in Sources */ = {isa = PBXBuildFile; fileRef = FEBCD5F91DD957AB00F55318 /* TestModel.m */; };
11 | FEBE61861D73D8B70066D757 /* SwipeView.m in Sources */ = {isa = PBXBuildFile; fileRef = FEBE61851D73D8B70066D757 /* SwipeView.m */; };
12 | FECCB0201D5C649D002FDD6C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FECCB01F1D5C649D002FDD6C /* main.m */; };
13 | FECCB0231D5C649D002FDD6C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FECCB0221D5C649D002FDD6C /* AppDelegate.m */; };
14 | FECCB0261D5C649D002FDD6C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FECCB0251D5C649D002FDD6C /* ViewController.m */; };
15 | FECCB0291D5C649D002FDD6C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FECCB0271D5C649D002FDD6C /* Main.storyboard */; };
16 | FECCB02B1D5C649D002FDD6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FECCB02A1D5C649D002FDD6C /* Assets.xcassets */; };
17 | FECCB02E1D5C649D002FDD6C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FECCB02C1D5C649D002FDD6C /* LaunchScreen.storyboard */; };
18 | FECCB03B1D5C65C7002FDD6C /* SwipeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = FECCB03A1D5C65C7002FDD6C /* SwipeButton.m */; };
19 | FECCB03E1D5C65E5002FDD6C /* SwipeTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FECCB03D1D5C65E5002FDD6C /* SwipeTableCell.m */; };
20 | /* End PBXBuildFile section */
21 |
22 | /* Begin PBXFileReference section */
23 | FEBCD5F81DD957AB00F55318 /* TestModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestModel.h; sourceTree = ""; };
24 | FEBCD5F91DD957AB00F55318 /* TestModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestModel.m; sourceTree = ""; };
25 | FEBE61841D73D8B70066D757 /* SwipeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwipeView.h; sourceTree = ""; };
26 | FEBE61851D73D8B70066D757 /* SwipeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwipeView.m; sourceTree = ""; };
27 | FECCB01B1D5C649D002FDD6C /* SwipeTableView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwipeTableView.app; sourceTree = BUILT_PRODUCTS_DIR; };
28 | FECCB01F1D5C649D002FDD6C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
29 | FECCB0211D5C649D002FDD6C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
30 | FECCB0221D5C649D002FDD6C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
31 | FECCB0241D5C649D002FDD6C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
32 | FECCB0251D5C649D002FDD6C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
33 | FECCB0281D5C649D002FDD6C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
34 | FECCB02A1D5C649D002FDD6C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
35 | FECCB02D1D5C649D002FDD6C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
36 | FECCB02F1D5C649D002FDD6C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
37 | FECCB0391D5C65C7002FDD6C /* SwipeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwipeButton.h; sourceTree = ""; };
38 | FECCB03A1D5C65C7002FDD6C /* SwipeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwipeButton.m; sourceTree = ""; };
39 | FECCB03C1D5C65E5002FDD6C /* SwipeTableCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwipeTableCell.h; sourceTree = ""; };
40 | FECCB03D1D5C65E5002FDD6C /* SwipeTableCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SwipeTableCell.m; sourceTree = ""; };
41 | /* End PBXFileReference section */
42 |
43 | /* Begin PBXFrameworksBuildPhase section */
44 | FECCB0181D5C649D002FDD6C /* Frameworks */ = {
45 | isa = PBXFrameworksBuildPhase;
46 | buildActionMask = 2147483647;
47 | files = (
48 | );
49 | runOnlyForDeploymentPostprocessing = 0;
50 | };
51 | /* End PBXFrameworksBuildPhase section */
52 |
53 | /* Begin PBXGroup section */
54 | FECCB0121D5C649D002FDD6C = {
55 | isa = PBXGroup;
56 | children = (
57 | FECCB0351D5C6550002FDD6C /* Swipe */,
58 | FECCB01D1D5C649D002FDD6C /* SwipeTableView */,
59 | FECCB01C1D5C649D002FDD6C /* Products */,
60 | );
61 | sourceTree = "";
62 | };
63 | FECCB01C1D5C649D002FDD6C /* Products */ = {
64 | isa = PBXGroup;
65 | children = (
66 | FECCB01B1D5C649D002FDD6C /* SwipeTableView.app */,
67 | );
68 | name = Products;
69 | sourceTree = "";
70 | };
71 | FECCB01D1D5C649D002FDD6C /* SwipeTableView */ = {
72 | isa = PBXGroup;
73 | children = (
74 | FECCB0211D5C649D002FDD6C /* AppDelegate.h */,
75 | FECCB0221D5C649D002FDD6C /* AppDelegate.m */,
76 | FECCB0241D5C649D002FDD6C /* ViewController.h */,
77 | FECCB0251D5C649D002FDD6C /* ViewController.m */,
78 | FEBCD5F81DD957AB00F55318 /* TestModel.h */,
79 | FEBCD5F91DD957AB00F55318 /* TestModel.m */,
80 | FECCB0271D5C649D002FDD6C /* Main.storyboard */,
81 | FECCB02A1D5C649D002FDD6C /* Assets.xcassets */,
82 | FECCB02C1D5C649D002FDD6C /* LaunchScreen.storyboard */,
83 | FECCB02F1D5C649D002FDD6C /* Info.plist */,
84 | FECCB01E1D5C649D002FDD6C /* Supporting Files */,
85 | );
86 | path = SwipeTableView;
87 | sourceTree = "";
88 | };
89 | FECCB01E1D5C649D002FDD6C /* Supporting Files */ = {
90 | isa = PBXGroup;
91 | children = (
92 | FECCB01F1D5C649D002FDD6C /* main.m */,
93 | );
94 | name = "Supporting Files";
95 | sourceTree = "";
96 | };
97 | FECCB0351D5C6550002FDD6C /* Swipe */ = {
98 | isa = PBXGroup;
99 | children = (
100 | FECCB0391D5C65C7002FDD6C /* SwipeButton.h */,
101 | FECCB03A1D5C65C7002FDD6C /* SwipeButton.m */,
102 | FECCB03C1D5C65E5002FDD6C /* SwipeTableCell.h */,
103 | FECCB03D1D5C65E5002FDD6C /* SwipeTableCell.m */,
104 | FEBE61841D73D8B70066D757 /* SwipeView.h */,
105 | FEBE61851D73D8B70066D757 /* SwipeView.m */,
106 | );
107 | path = Swipe;
108 | sourceTree = "";
109 | };
110 | /* End PBXGroup section */
111 |
112 | /* Begin PBXNativeTarget section */
113 | FECCB01A1D5C649D002FDD6C /* SwipeTableView */ = {
114 | isa = PBXNativeTarget;
115 | buildConfigurationList = FECCB0321D5C649D002FDD6C /* Build configuration list for PBXNativeTarget "SwipeTableView" */;
116 | buildPhases = (
117 | FECCB0171D5C649D002FDD6C /* Sources */,
118 | FECCB0181D5C649D002FDD6C /* Frameworks */,
119 | FECCB0191D5C649D002FDD6C /* Resources */,
120 | );
121 | buildRules = (
122 | );
123 | dependencies = (
124 | );
125 | name = SwipeTableView;
126 | productName = SwipeTableView;
127 | productReference = FECCB01B1D5C649D002FDD6C /* SwipeTableView.app */;
128 | productType = "com.apple.product-type.application";
129 | };
130 | /* End PBXNativeTarget section */
131 |
132 | /* Begin PBXProject section */
133 | FECCB0131D5C649D002FDD6C /* Project object */ = {
134 | isa = PBXProject;
135 | attributes = {
136 | LastUpgradeCheck = 0730;
137 | ORGANIZATIONNAME = zhaoName;
138 | TargetAttributes = {
139 | FECCB01A1D5C649D002FDD6C = {
140 | CreatedOnToolsVersion = 7.3.1;
141 | DevelopmentTeam = C286J3CQWQ;
142 | ProvisioningStyle = Automatic;
143 | };
144 | };
145 | };
146 | buildConfigurationList = FECCB0161D5C649D002FDD6C /* Build configuration list for PBXProject "SwipeTableView" */;
147 | compatibilityVersion = "Xcode 3.2";
148 | developmentRegion = English;
149 | hasScannedForEncodings = 0;
150 | knownRegions = (
151 | en,
152 | Base,
153 | );
154 | mainGroup = FECCB0121D5C649D002FDD6C;
155 | productRefGroup = FECCB01C1D5C649D002FDD6C /* Products */;
156 | projectDirPath = "";
157 | projectRoot = "";
158 | targets = (
159 | FECCB01A1D5C649D002FDD6C /* SwipeTableView */,
160 | );
161 | };
162 | /* End PBXProject section */
163 |
164 | /* Begin PBXResourcesBuildPhase section */
165 | FECCB0191D5C649D002FDD6C /* Resources */ = {
166 | isa = PBXResourcesBuildPhase;
167 | buildActionMask = 2147483647;
168 | files = (
169 | FECCB02E1D5C649D002FDD6C /* LaunchScreen.storyboard in Resources */,
170 | FECCB02B1D5C649D002FDD6C /* Assets.xcassets in Resources */,
171 | FECCB0291D5C649D002FDD6C /* Main.storyboard in Resources */,
172 | );
173 | runOnlyForDeploymentPostprocessing = 0;
174 | };
175 | /* End PBXResourcesBuildPhase section */
176 |
177 | /* Begin PBXSourcesBuildPhase section */
178 | FECCB0171D5C649D002FDD6C /* Sources */ = {
179 | isa = PBXSourcesBuildPhase;
180 | buildActionMask = 2147483647;
181 | files = (
182 | FECCB03B1D5C65C7002FDD6C /* SwipeButton.m in Sources */,
183 | FECCB0261D5C649D002FDD6C /* ViewController.m in Sources */,
184 | FEBE61861D73D8B70066D757 /* SwipeView.m in Sources */,
185 | FECCB03E1D5C65E5002FDD6C /* SwipeTableCell.m in Sources */,
186 | FECCB0231D5C649D002FDD6C /* AppDelegate.m in Sources */,
187 | FECCB0201D5C649D002FDD6C /* main.m in Sources */,
188 | FEBCD5FA1DD957AB00F55318 /* TestModel.m in Sources */,
189 | );
190 | runOnlyForDeploymentPostprocessing = 0;
191 | };
192 | /* End PBXSourcesBuildPhase section */
193 |
194 | /* Begin PBXVariantGroup section */
195 | FECCB0271D5C649D002FDD6C /* Main.storyboard */ = {
196 | isa = PBXVariantGroup;
197 | children = (
198 | FECCB0281D5C649D002FDD6C /* Base */,
199 | );
200 | name = Main.storyboard;
201 | sourceTree = "";
202 | };
203 | FECCB02C1D5C649D002FDD6C /* LaunchScreen.storyboard */ = {
204 | isa = PBXVariantGroup;
205 | children = (
206 | FECCB02D1D5C649D002FDD6C /* Base */,
207 | );
208 | name = LaunchScreen.storyboard;
209 | sourceTree = "";
210 | };
211 | /* End PBXVariantGroup section */
212 |
213 | /* Begin XCBuildConfiguration section */
214 | FECCB0301D5C649D002FDD6C /* Debug */ = {
215 | isa = XCBuildConfiguration;
216 | buildSettings = {
217 | ALWAYS_SEARCH_USER_PATHS = NO;
218 | CLANG_ANALYZER_NONNULL = YES;
219 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
220 | CLANG_CXX_LIBRARY = "libc++";
221 | CLANG_ENABLE_MODULES = YES;
222 | CLANG_ENABLE_OBJC_ARC = YES;
223 | CLANG_WARN_BOOL_CONVERSION = YES;
224 | CLANG_WARN_CONSTANT_CONVERSION = YES;
225 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
226 | CLANG_WARN_EMPTY_BODY = YES;
227 | CLANG_WARN_ENUM_CONVERSION = YES;
228 | CLANG_WARN_INT_CONVERSION = YES;
229 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
230 | CLANG_WARN_UNREACHABLE_CODE = YES;
231 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
232 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
233 | COPY_PHASE_STRIP = NO;
234 | DEBUG_INFORMATION_FORMAT = dwarf;
235 | ENABLE_STRICT_OBJC_MSGSEND = YES;
236 | ENABLE_TESTABILITY = YES;
237 | GCC_C_LANGUAGE_STANDARD = gnu99;
238 | GCC_DYNAMIC_NO_PIC = NO;
239 | GCC_NO_COMMON_BLOCKS = YES;
240 | GCC_OPTIMIZATION_LEVEL = 0;
241 | GCC_PREPROCESSOR_DEFINITIONS = (
242 | "DEBUG=1",
243 | "$(inherited)",
244 | );
245 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
246 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
247 | GCC_WARN_UNDECLARED_SELECTOR = YES;
248 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
249 | GCC_WARN_UNUSED_FUNCTION = YES;
250 | GCC_WARN_UNUSED_VARIABLE = YES;
251 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
252 | MTL_ENABLE_DEBUG_INFO = YES;
253 | ONLY_ACTIVE_ARCH = YES;
254 | SDKROOT = iphoneos;
255 | };
256 | name = Debug;
257 | };
258 | FECCB0311D5C649D002FDD6C /* Release */ = {
259 | isa = XCBuildConfiguration;
260 | buildSettings = {
261 | ALWAYS_SEARCH_USER_PATHS = NO;
262 | CLANG_ANALYZER_NONNULL = YES;
263 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
264 | CLANG_CXX_LIBRARY = "libc++";
265 | CLANG_ENABLE_MODULES = YES;
266 | CLANG_ENABLE_OBJC_ARC = YES;
267 | CLANG_WARN_BOOL_CONVERSION = YES;
268 | CLANG_WARN_CONSTANT_CONVERSION = YES;
269 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
270 | CLANG_WARN_EMPTY_BODY = YES;
271 | CLANG_WARN_ENUM_CONVERSION = YES;
272 | CLANG_WARN_INT_CONVERSION = YES;
273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
274 | CLANG_WARN_UNREACHABLE_CODE = YES;
275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
276 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
277 | COPY_PHASE_STRIP = NO;
278 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
279 | ENABLE_NS_ASSERTIONS = NO;
280 | ENABLE_STRICT_OBJC_MSGSEND = YES;
281 | GCC_C_LANGUAGE_STANDARD = gnu99;
282 | GCC_NO_COMMON_BLOCKS = YES;
283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
284 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
285 | GCC_WARN_UNDECLARED_SELECTOR = YES;
286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
287 | GCC_WARN_UNUSED_FUNCTION = YES;
288 | GCC_WARN_UNUSED_VARIABLE = YES;
289 | IPHONEOS_DEPLOYMENT_TARGET = 9.3;
290 | MTL_ENABLE_DEBUG_INFO = NO;
291 | SDKROOT = iphoneos;
292 | VALIDATE_PRODUCT = YES;
293 | };
294 | name = Release;
295 | };
296 | FECCB0331D5C649D002FDD6C /* Debug */ = {
297 | isa = XCBuildConfiguration;
298 | buildSettings = {
299 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
300 | CODE_SIGN_IDENTITY = "iPhone Developer";
301 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
302 | DEVELOPMENT_TEAM = C286J3CQWQ;
303 | INFOPLIST_FILE = SwipeTableView/Info.plist;
304 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
305 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
306 | PRODUCT_BUNDLE_IDENTIFIER = zhao.SwipeTableView;
307 | PRODUCT_NAME = "$(TARGET_NAME)";
308 | PROVISIONING_PROFILE = "";
309 | PROVISIONING_PROFILE_SPECIFIER = "";
310 | };
311 | name = Debug;
312 | };
313 | FECCB0341D5C649D002FDD6C /* Release */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
317 | CODE_SIGN_IDENTITY = "iPhone Developer";
318 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
319 | DEVELOPMENT_TEAM = C286J3CQWQ;
320 | INFOPLIST_FILE = SwipeTableView/Info.plist;
321 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
322 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
323 | PRODUCT_BUNDLE_IDENTIFIER = zhao.SwipeTableView;
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | PROVISIONING_PROFILE = "";
326 | PROVISIONING_PROFILE_SPECIFIER = "";
327 | };
328 | name = Release;
329 | };
330 | /* End XCBuildConfiguration section */
331 |
332 | /* Begin XCConfigurationList section */
333 | FECCB0161D5C649D002FDD6C /* Build configuration list for PBXProject "SwipeTableView" */ = {
334 | isa = XCConfigurationList;
335 | buildConfigurations = (
336 | FECCB0301D5C649D002FDD6C /* Debug */,
337 | FECCB0311D5C649D002FDD6C /* Release */,
338 | );
339 | defaultConfigurationIsVisible = 0;
340 | defaultConfigurationName = Release;
341 | };
342 | FECCB0321D5C649D002FDD6C /* Build configuration list for PBXNativeTarget "SwipeTableView" */ = {
343 | isa = XCConfigurationList;
344 | buildConfigurations = (
345 | FECCB0331D5C649D002FDD6C /* Debug */,
346 | FECCB0341D5C649D002FDD6C /* Release */,
347 | );
348 | defaultConfigurationIsVisible = 0;
349 | defaultConfigurationName = Release;
350 | };
351 | /* End XCConfigurationList section */
352 | };
353 | rootObject = FECCB0131D5C649D002FDD6C /* Project object */;
354 | }
355 |
--------------------------------------------------------------------------------
/Swipe/SwipeTableCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeTableCell.m
3 | // SwipeTableView
4 | //
5 | // Created by zhao on 16/8/11.
6 | // Copyright © 2016年 zhaoName. All rights reserved.
7 | //
8 |
9 | #import "SwipeTableCell.h"
10 |
11 | #define CELL_WIDTH self.bounds.size.width
12 | #define CELL_HEIGHT self.bounds.size.height
13 |
14 |
15 | @interface SwipeTableCell ()
16 |
17 | @property (nonatomic, strong) UITableView *tableView; /**< 当前cell所在的tableView*/
18 | @property (nonatomic, strong) UIView *swipeOverlayView; /**< 滑动时覆盖在cell上*/
19 | @property (nonatomic, strong) UIImageView *swipeImageView; /**< 显示移动后的cell上的内容*/
20 | @property (nonatomic, strong) SwipeView *rightSwipeView; /**< 右滑展示的view*/
21 | @property (nonatomic, strong) SwipeView *leftSwipeView; /**< 左滑展示的View*/
22 | @property (nonatomic, strong) SwipeView *gestureAnimationSwipeView;
23 |
24 | @property (nonatomic, assign) SwipeTableCellStyle swipeStyle; /**< 滑动样式 默认右滑*/
25 | @property (nonatomic, assign) SwipeViewTransfromMode transformMode; /**< swipeView的弹出效果*/
26 | @property (nonatomic, strong) NSArray *leftSwipeButtons; /**< 左滑buttons*/
27 | @property (nonatomic, strong) NSArray *rightSwipeButtons; /**< 右滑buttons*/
28 | @property (nonatomic, strong) NSMutableSet *perviusHiddenViewSet;/**< 已经隐藏的view*/
29 |
30 | @property (nonatomic, assign) CGFloat swipeOffset; /**< 滑动偏移量*/
31 | @property (nonatomic, assign) CGFloat targetOffset; /**< 最终目标偏移量*/
32 | @property (nonatomic, strong) UIPanGestureRecognizer *panGesture; /**< 滑动手势*/
33 | @property (nonatomic, strong) UITapGestureRecognizer *tapGesture; /**< 点击手势*/
34 |
35 | @property (nonatomic, assign) CGPoint panStartPoint; /**<滑动手势开始点击的坐标*/
36 | @property (nonatomic, assign) CGFloat panStartOffset; /**<滑动手势的偏移量*/
37 | @property (nonatomic, assign) BOOL isShowSwipeOverlayView; /**< 保证显示、隐藏swipeImageView方法只走一次*/
38 |
39 | @property (nonatomic, strong) CADisplayLink *dispalyLink; /**<定时器 一秒60次*/
40 | @property (nonatomic, assign) UITableViewCellSelectionStyle previousSelectStyle;/**< 先前cell的选中样式*/
41 |
42 | @end
43 |
44 | @implementation SwipeTableCell
45 |
46 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
47 | {
48 | if([super initWithStyle:style reuseIdentifier:reuseIdentifier])
49 | {
50 | [self initDatas];
51 | }
52 | return self;
53 | }
54 |
55 | - (instancetype)initWithCoder:(NSCoder *)aDecoder
56 | {
57 | if([super initWithCoder:aDecoder])
58 | {
59 | [self initDatas];
60 | }
61 | return self;
62 | }
63 |
64 | - (void)awakeFromNib
65 | {
66 | [super awakeFromNib];
67 | [self initDatas];
68 | }
69 |
70 | /**
71 | * 初始化数据
72 | */
73 | - (void)initDatas
74 | {
75 | self.swipeStyle = SwipeTableCellStyleRightToLeft; //默认右滑
76 | self.transformMode = SwipeViewTransfromModeDefault;
77 | self.swipeOffset = 0.0;
78 | self.targetOffset = 0.0;
79 | self.swipeThreshold = 0.5;
80 | self.isAllowMultipleSwipe = NO;
81 | self.isShowSwipeOverlayView = NO;
82 | _hideSwipeViewWhenScrollTableView = YES;
83 | self.hideSwipeViewWhenClickSwipeButton = YES;
84 | self.swipeOverlayViewBackgroundColor = [UIColor clearColor];
85 | self.selectionStyle = UITableViewCellSelectionStyleNone;
86 |
87 | self.isAllowExpand = YES;
88 | self.expandThreshold = 1.5;
89 |
90 | self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGestureRecognizer:)];
91 | self.panGesture.delegate = self;
92 | [self addGestureRecognizer:self.panGesture];
93 | }
94 |
95 | /**
96 | * 复用问题
97 | */
98 | - (void)prepareForReuse
99 | {
100 | [super prepareForReuse];
101 |
102 | if(self.panGesture)
103 | {
104 | self.panGesture.delegate = nil;
105 | [self removeGestureRecognizer:self.panGesture];
106 | self.panGesture = nil;
107 | }
108 | if(self.swipeOverlayView)
109 | {
110 | [self.swipeOverlayView removeFromSuperview];
111 | self.swipeOverlayView = nil;
112 | _rightSwipeView = _leftSwipeView = nil;
113 | self.rightSwipeButtons = @[];
114 | self.leftSwipeButtons = @[];
115 | }
116 | if(self.dispalyLink)
117 | {
118 | [self.dispalyLink invalidate];
119 | self.dispalyLink = nil;
120 | }
121 | [self initDatas];
122 | }
123 |
124 | - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
125 | {
126 | UIView *view = [super hitTest:point withEvent:event];
127 |
128 | if (!view)
129 | {
130 | // bug fixed: swipeView显示后再次拖动swipeView 会出现快速闪动现象
131 | NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:point];
132 | if (indexPath != nil || point.y < 0) return view;
133 |
134 | // 若点击区域在tableView上 而不在cell上,滑动时也会自动隐藏swipeView
135 | for(SwipeTableCell *cell in self.tableView.visibleCells) // 滑动cell时,自动隐藏swipeView
136 | {
137 | if(cell.hideSwipeViewWhenScrollTableView && !cell.swipeOverlayView.hidden)
138 | {
139 | [cell hiddenSwipeAnimationAtCell:YES];
140 | }
141 | }
142 | }
143 | return view;
144 | }
145 |
146 | // 更改滑动按钮的内容 如置顶变成取消置顶
147 | - (void)refreshButtonContent
148 | {
149 | if(self.rightSwipeView)
150 | {
151 | [self.rightSwipeView removeFromSuperview];
152 | self.rightSwipeView = nil;
153 | }
154 | if(self.leftSwipeView)
155 | {
156 | [self.leftSwipeView removeFromSuperview];
157 | self.leftSwipeView = nil;
158 | }
159 | self.rightSwipeButtons = @[];
160 | self.leftSwipeButtons = @[];
161 |
162 | [self getSwipeButtons];
163 | [self createSwipeOverlayViewIfNeed];
164 | }
165 |
166 | #pragma mark -- 处理滑动手势
167 | /**
168 | * 处理滑动手势 上左x<0、y<0 下右x>0、y>0
169 | */
170 | - (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)pan
171 | {
172 | CGPoint currentPanPoint = [pan translationInView:self];
173 |
174 | if(pan.state == UIGestureRecognizerStateBegan)
175 | {
176 | self.panStartPoint = currentPanPoint;
177 | self.panStartOffset = self.swipeOffset;
178 |
179 | [self createSwipeOverlayViewIfNeed];
180 | // 不允许多个cell同时能滑动,则移除上一个cell的滑动手势
181 | if(!_isAllowMultipleSwipe)
182 | {
183 | for(SwipeTableCell * cell in self.tableView.visibleCells)
184 | {
185 | if(cell != self) [cell cancelPanGesture];
186 | }
187 | }
188 | }
189 | else if(pan.state == UIGestureRecognizerStateChanged)
190 | {
191 | CGFloat offset = self.panStartOffset + currentPanPoint.x - self.panStartPoint.x;
192 | // 重新swipeOffset的setter方法,监测滑动偏移量
193 | self.swipeOffset = [self filterSwipeOffset:offset];
194 | }
195 | else if(pan.state == UIGestureRecognizerStateEnded)
196 | {
197 | CGFloat velocity = [self.panGesture velocityInView:self].x;
198 | CGFloat inertiaThreshold = 300; // 每秒走过多少像素
199 |
200 | if(velocity > inertiaThreshold) // 快速左滑
201 | {
202 | self.targetOffset = self.swipeOffset < 0 ? 0 : (self.leftSwipeView ? self.leftSwipeView.frame.size.width : self.targetOffset);
203 | }
204 | else if(velocity < -inertiaThreshold) // 快速右滑
205 | {
206 | self.targetOffset = self.swipeOffset > 0 ? 0 : (self.rightSwipeView ? -self.rightSwipeView.frame.size.width : self.targetOffset);
207 | }
208 |
209 | self.targetOffset = [self filterSwipeOffset:self.targetOffset];
210 | //NSLog(@"targetOffset:%f", self.targetOffset);
211 | [self gestureAnimationWithOffset:self.targetOffset animationView:self.targetOffset <= 0 ? self.rightSwipeView : self.leftSwipeView];
212 | }
213 | }
214 |
215 | /**
216 | * 创建用于显示滑动过后cell内容的SwipeImageView, 并在其上添加滑动按钮
217 | */
218 | - (void)createSwipeOverlayViewIfNeed
219 | {
220 | [self getSwipeTableViewCellStyle];
221 | [self getSwipeButtons];
222 |
223 | if(!self.swipeOverlayView)
224 | {
225 | _swipeOverlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CELL_WIDTH, CELL_HEIGHT)];
226 | _swipeOverlayView.backgroundColor = self.swipeOverlayViewBackgroundColor;
227 | _swipeOverlayView.hidden = YES;
228 |
229 | _swipeImageView = [[UIImageView alloc] initWithFrame:self.swipeOverlayView.bounds];
230 | _swipeImageView.userInteractionEnabled = YES;
231 |
232 | [_swipeOverlayView addSubview:_swipeImageView];
233 | [self.contentView addSubview:self.swipeOverlayView];
234 | }
235 |
236 | // 获取swipeButton距swipeTableView上左下右的距离
237 | UIEdgeInsets edge = UIEdgeInsetsZero;
238 | if ([self.swipeDelegate respondsToSelector:@selector(tableView:swipeButtonEdgeAtIndexPath:)]) {
239 | edge = [self.swipeDelegate tableView:self.tableView swipeButtonEdgeAtIndexPath:[self.tableView indexPathForCell:self]];
240 | }
241 | if(self.rightSwipeButtons.count && !self.rightSwipeView)
242 | {
243 | _rightSwipeView = [[SwipeView alloc] initWithButtons:self.rightSwipeButtons fromRight:YES cellHeght:CELL_HEIGHT edge:edge];
244 | // 改变rightSwipeView的frame 使其显示在swipeImageView的最右端
245 | _rightSwipeView.frame = CGRectMake(self.swipeImageView.bounds.size.width, 0, _rightSwipeView.frame.size.width, CELL_HEIGHT);
246 | [self.swipeOverlayView addSubview:_rightSwipeView];
247 | }
248 | if(self.leftSwipeButtons.count && !self.leftSwipeView)
249 | {
250 | _leftSwipeView = [[SwipeView alloc] initWithButtons:self.leftSwipeButtons fromRight:NO cellHeght:CELL_HEIGHT edge:edge];
251 | // 改变leftSwipeView的frame 使其显示在swipeImageView的最左端
252 | _leftSwipeView.frame = CGRectMake(-_leftSwipeView.frame.size.width, 0, _leftSwipeView.frame.size.width, CELL_HEIGHT);
253 | [self.swipeOverlayView addSubview:_leftSwipeView];
254 | }
255 | }
256 |
257 | /**
258 | * 判断滑动是否合法 并返回滑动距离
259 | */
260 | - (CGFloat)filterSwipeOffset:(CGFloat)offset
261 | {
262 | UIView *swipeView = offset > 0 ? self.leftSwipeView : self.rightSwipeView;
263 | if(!swipeView)
264 | {
265 | return 0.0;
266 | }
267 | else if(self.swipeStyle == SwipeTableCellStyleLeftToRight && offset < 0)
268 | {
269 | return 0.0;
270 | }
271 | else if(self.swipeStyle == SwipeTableCellStyleRightToLeft && offset > 0)
272 | {
273 | return 0.0;
274 | }
275 | return offset;
276 | }
277 |
278 | /**
279 | * 当滑动下一个cell时 取消上一个cell的滑动手势
280 | */
281 | - (void)cancelPanGesture
282 | {
283 | self.panGesture.enabled = NO;
284 | self.panGesture.enabled = YES;
285 | // 将上一个cell恢复原状
286 | if(self.swipeOffset){
287 | [self hiddenSwipeAnimationAtCell:YES];
288 | }
289 | }
290 |
291 | #pragma mark -- 处理点击手势
292 |
293 | - (void)handleTapGesture:(UITapGestureRecognizer *)tapGesture
294 | {
295 | BOOL hidden = YES;
296 | if([self.swipeDelegate respondsToSelector:@selector(tableView:hiddenSwipeViewWhenTapCellAtIndexPath:)])
297 | {
298 | // 判断点击cell是否隐藏swipeView
299 | hidden = [self.swipeDelegate tableView:self.tableView hiddenSwipeViewWhenTapCellAtIndexPath:[self.tableView indexPathForCell:self]];
300 | }
301 | if(hidden)
302 | {
303 | [self hiddenSwipeAnimationAtCell:YES];
304 | }
305 | }
306 |
307 | #pragma mark -- 处理手势动画效果
308 |
309 | /**
310 | * 隐藏滑动按钮 即将cell恢复原状
311 | *
312 | * @param isAnimation 是否隐藏
313 | */
314 | - (void)hiddenSwipeAnimationAtCell:(BOOL)isAnimation
315 | {
316 | SwipeView *aView = self.swipeOffset < 0 ? self.rightSwipeView : self.leftSwipeView;
317 | [self gestureAnimationWithOffset:isAnimation ? 0 : self.swipeOffset animationView:aView];
318 | }
319 |
320 | /**
321 | * 隐藏或显示滑动按钮的动画
322 | *
323 | * @param offset 滑动按钮的偏移量
324 | * @param animationView 右滑或左滑View
325 | */
326 | - (void)gestureAnimationWithOffset:(CGFloat)offset animationView:(SwipeView *)animationView
327 | {
328 | self.gestureAnimationSwipeView = animationView;
329 | if(self.dispalyLink){
330 | [self.dispalyLink invalidate];
331 | self.dispalyLink = nil;
332 | }
333 |
334 | if(offset !=0 ){
335 | [self createSwipeOverlayViewIfNeed];
336 | }
337 |
338 | if(!self.gestureAnimationSwipeView){
339 | self.swipeOffset = offset;
340 | return;
341 | }
342 |
343 | self.gestureAnimationSwipeView.from = self.swipeOffset;
344 | self.gestureAnimationSwipeView.to = offset;
345 | self.gestureAnimationSwipeView.start = 0;
346 | self.dispalyLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleAnimation:)];
347 | [self.dispalyLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
348 | }
349 |
350 | /**
351 | * 定时器处理动画
352 | */
353 | - (void)handleAnimation:(CADisplayLink *)link
354 | {
355 | if (!self.gestureAnimationSwipeView.start) {
356 | self.gestureAnimationSwipeView.start = link.timestamp;
357 | }
358 |
359 | CFTimeInterval elapsed = link.timestamp - self.gestureAnimationSwipeView.start;
360 | //滑动超过SwipeView的一半 自动显示或隐藏全部内容
361 | self.swipeOffset = [self.gestureAnimationSwipeView value:elapsed duration:self.gestureAnimationSwipeView.duration from:self.gestureAnimationSwipeView.from to:self.gestureAnimationSwipeView.to];
362 |
363 | if(elapsed >= self.gestureAnimationSwipeView.duration)
364 | {
365 | [link invalidate];
366 | self.dispalyLink = nil;
367 | }
368 | }
369 |
370 | #pragma mark -- UIGestureRecognizerDelegates
371 |
372 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
373 | {
374 | if([gestureRecognizer isEqual:self.panGesture])
375 | {
376 | if(self.editing) return NO; // tableView在编辑状态
377 |
378 | if(self.targetOffset != 0.0) return YES; // 已经在滑动状态
379 |
380 | // 使UITableView可以滚动 解决滑动tableView和滑动cell冲突的问题
381 | CGPoint panPoint = [self.panGesture translationInView:self];
382 | if(fabs(panPoint.x) < fabs(panPoint.y))
383 | {
384 | for(SwipeTableCell *cell in self.tableView.visibleCells) // 滑动cell时,自动隐藏swipeView
385 | {
386 | if(cell.hideSwipeViewWhenScrollTableView && !cell.swipeOverlayView.hidden)
387 | {
388 | [cell hiddenSwipeAnimationAtCell:YES];
389 | }
390 | }
391 | return NO;
392 | }
393 | }
394 | else if(gestureRecognizer == self.tapGesture)
395 | {
396 | //解决和didSelect冲突问题
397 | CGPoint tapPoint = [self.tapGesture locationInView:self];
398 | //NSLog(@"%@,%@", NSStringFromCGRect(self.swipeOverlayView.frame), NSStringFromCGPoint(tapPoint));
399 | return CGRectContainsPoint(self.swipeImageView.frame, tapPoint);
400 | }
401 | return YES;
402 | }
403 |
404 | #pragma mark -- 获取滑动按钮、滑动按钮的样式
405 | /**
406 | * 获取滑动button的样式
407 | */
408 | - (void)getSwipeTableViewCellStyle
409 | {
410 | NSIndexPath *indexPath = [self.tableView indexPathForCell:self];
411 | if([self.swipeDelegate respondsToSelector:@selector(tableView: styleOfSwipeButtonForRowAtIndexPath:)])
412 | {
413 | self.swipeStyle = [self.swipeDelegate tableView:self.tableView styleOfSwipeButtonForRowAtIndexPath:indexPath];
414 | }
415 | }
416 |
417 | /**
418 | * 获取滑动button
419 | */
420 | - (void)getSwipeButtons
421 | {
422 | NSIndexPath *indexPath = [self.tableView indexPathForCell:self];
423 | if(self.swipeStyle == SwipeTableCellStyleRightToLeft)
424 | {
425 | if([self.swipeDelegate respondsToSelector:@selector(tableView: rightSwipeButtonsAtIndexPath:)])
426 | {
427 | self.rightSwipeButtons = [[self.swipeDelegate tableView:self.tableView rightSwipeButtonsAtIndexPath:indexPath] mutableCopy];
428 | }
429 | }
430 | else if(self.swipeStyle == SwipeTableCellStyleLeftToRight)
431 | {
432 | if([self.swipeDelegate respondsToSelector:@selector(tableView : leftSwipeButtonsAtIndexPath:)])
433 | {
434 | self.leftSwipeButtons = [self.swipeDelegate tableView:self.tableView leftSwipeButtonsAtIndexPath:indexPath];
435 | }
436 | }
437 | else if(self.swipeStyle == SwipeTableCellStyleBoth)
438 | {
439 | if([self.swipeDelegate respondsToSelector:@selector(tableView: rightSwipeButtonsAtIndexPath:)])
440 | {
441 | self.rightSwipeButtons = [self.swipeDelegate tableView:self.tableView rightSwipeButtonsAtIndexPath:indexPath];
442 | }
443 |
444 | if([self.swipeDelegate respondsToSelector:@selector(tableView : leftSwipeButtonsAtIndexPath:)])
445 | {
446 | self.leftSwipeButtons = [self.swipeDelegate tableView:self.tableView leftSwipeButtonsAtIndexPath:indexPath];
447 | }
448 | }
449 | }
450 |
451 | - (void)getSwipeViewTransformMode
452 | {
453 | if([self.swipeDelegate respondsToSelector:@selector(tableView:swipeViewTransformModeAtIndexPath:)])
454 | {
455 | self.transformMode = [self.swipeDelegate tableView:self.tableView swipeViewTransformModeAtIndexPath:[self.tableView indexPathForCell:self]];
456 | }
457 | }
458 |
459 | #pragma mark -- 私有方法
460 |
461 | /**
462 | * 截取平移过后的cell上的内容 以图片的形式显示出来
463 | */
464 | - (UIImage *)fecthTranslatedCellInfo:(UIView *)cell
465 | {
466 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
467 | [cell.layer renderInContext:UIGraphicsGetCurrentContext()];
468 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
469 | UIGraphicsEndImageContext();
470 | return image;
471 | }
472 |
473 | /** 删除所有子视图*/
474 | - (void)removeAllSubViewsAtView:(UIView *)view
475 | {
476 | while (view.subviews.count) {
477 | [[view.subviews lastObject] removeFromSuperview];
478 | }
479 | }
480 |
481 | #pragma mark -- 显示、隐藏cell上的内容
482 | /**
483 | * 显示self.swipeImageView
484 | */
485 | - (void)showSwipeOverlayViewIfNeed
486 | {
487 | if(self.isShowSwipeOverlayView) return;
488 | self.isShowSwipeOverlayView = YES;
489 |
490 | // 去除cell的选中状态,并保存
491 | self.selected = NO;
492 | self.previousSelectStyle = self.selectionStyle;
493 | self.selectionStyle = UITableViewCellSelectionStyleNone;
494 |
495 | // 显示swipeOverlayView,并将移动后cell上的内容裁剪到swipeImageView上
496 | self.swipeImageView.image = [self fecthTranslatedCellInfo:self];
497 | self.swipeOverlayView.hidden = NO;
498 | self.swipeImageView.userInteractionEnabled = YES;
499 |
500 | // 隐藏cell上的内容
501 | [self hiddenAccesoryViewAndContentOfCellIfNeed:YES];
502 | // 添加点击手势
503 | self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
504 | self.tapGesture.delegate = self;
505 | [self.swipeImageView addGestureRecognizer:self.tapGesture];
506 | }
507 |
508 | /**
509 | * 隐藏self.swipeImageView
510 | */
511 | - (void)hiddenSwipeOverlayViewIfNeed
512 | {
513 | if(!self.isShowSwipeOverlayView) return;
514 | self.isShowSwipeOverlayView = NO;
515 |
516 | // 隐藏swipeImageView
517 | self.swipeOverlayView.hidden = YES;
518 | self.swipeImageView.image = nil;
519 | self.swipeImageView.userInteractionEnabled = NO;
520 |
521 | // 若cell是选中状态 则滑动手势结束后还原cell的选中状态
522 | self.selectionStyle = self.previousSelectStyle;
523 | NSArray *selectCells = self.tableView.indexPathsForSelectedRows;
524 | if([selectCells containsObject:[self.tableView indexPathForCell:self]])
525 | {
526 | self.selected = NO;
527 | self.selected = YES;
528 | }
529 |
530 | // 将cell上的内容还原
531 | [self hiddenAccesoryViewAndContentOfCellIfNeed:NO];
532 | // 移除点击手势
533 | if(self.tapGesture){
534 | [self.swipeImageView removeGestureRecognizer:self.tapGesture];
535 | self.tapGesture = nil;
536 | }
537 | }
538 |
539 | /**
540 | * 是否隐藏accesoryView和cell上的内容,从而使得滑动cell时不会看见原有cell上的内容
541 | */
542 | - (void)hiddenAccesoryViewAndContentOfCellIfNeed:(BOOL)hidden
543 | {
544 | // 若只设置self.accessoryType 则不走这个判断语句
545 | if(self.accessoryView){
546 | self.accessoryView.hidden = hidden;
547 | }
548 |
549 | // 设置了self.accessoryType 其实是个UIButton
550 | for(UIView *subView in self.contentView.superview.subviews)
551 | {
552 | if(subView != self.contentView && ([subView isKindOfClass:[UIButton class]] || [NSStringFromClass(subView.class) rangeOfString:@"Disclosure"].location != NSNotFound))
553 | {
554 | subView.hidden = hidden;
555 | }
556 | }
557 |
558 | for(UIView *subView in self.contentView.superview.subviews)
559 | {
560 | if (subView == self.contentView) continue;
561 | // 若是cell上的subView则隐藏
562 | if(hidden && !subView.hidden)
563 | {
564 | subView.hidden = YES;
565 | [self.perviusHiddenViewSet addObject:subView];
566 | }
567 | // 还原cell时,将隐藏的cell上的内容显示出来
568 | else if(!hidden && [self.perviusHiddenViewSet containsObject:subView])
569 | {
570 | subView.hidden = NO;
571 | }
572 | }
573 | if(!hidden){
574 | [self.perviusHiddenViewSet removeAllObjects];
575 | }
576 | }
577 |
578 | #pragma mark -- getter或setter
579 |
580 | /**重写tableView的getter方法 获取cell所在的tableView*/
581 | - (UITableView *)tableView
582 | {
583 | if(_tableView){
584 | return _tableView;
585 | }
586 | // 获取当前cell所在的父tableView
587 | UIView *view = self.superview;
588 | while (view != nil)
589 | {
590 | if([view isKindOfClass:[UITableView class]])
591 | {
592 | _tableView = (UITableView *)view;
593 | }
594 | view = view.superview;
595 | }
596 | return _tableView;
597 | }
598 |
599 | /** 重写swipeOffset的setter方法 监测滑动手势*/
600 | - (void)setSwipeOffset:(CGFloat)swipeOffset
601 | {
602 | CGFloat sign = swipeOffset > 0 ? 1 : -1;
603 | SwipeView *currentSwipeView = swipeOffset < 0 ? self.rightSwipeView : self.leftSwipeView;
604 |
605 | _swipeOffset = swipeOffset;
606 | CGFloat offset = fabs(_swipeOffset);
607 |
608 | if(!currentSwipeView || offset == 0)
609 | {
610 | [self hiddenSwipeOverlayViewIfNeed];
611 | self.targetOffset = 0.0;
612 | return;
613 | }
614 | else
615 | {
616 | [self showSwipeOverlayViewIfNeed];
617 | self.targetOffset = offset > currentSwipeView.bounds.size.width*self.swipeThreshold ? currentSwipeView.bounds.size.width*sign : 0;
618 | }
619 | //NSLog(@"self.swipeOffset:%f", self.swipeOffset);
620 | // 平移swipeImageView,显示滑动后cell的内容
621 | self.swipeImageView.transform = CGAffineTransformMakeTranslation(self.swipeOffset, 0);
622 |
623 | SwipeView *viewArray[2] = {self.rightSwipeView, self.leftSwipeView};
624 | for (int i = 0; i< 2; i++)
625 | {
626 | SwipeView *swipeView = viewArray[i];
627 | if(!swipeView) continue;
628 |
629 | BOOL expand = self.isAllowExpand && offset > currentSwipeView.frame.size.width * self.expandThreshold;
630 | // 拉伸
631 | if (expand)
632 | {
633 | self.targetOffset = currentSwipeView.frame.size.width * sign;
634 |
635 | }
636 | else
637 | {
638 | // 平移显示按钮
639 | CGFloat translation = MIN(offset, currentSwipeView.bounds.size.width)*sign;
640 | swipeView.transform = CGAffineTransformMakeTranslation(translation, 0);
641 | if(currentSwipeView != swipeView) continue;
642 |
643 | [self getSwipeViewTransformMode];
644 | currentSwipeView.mode = self.transformMode;
645 | CGFloat t = MIN(1.0f, offset/currentSwipeView.bounds.size.width);
646 | // swipeView的弹出、隐藏动画效果
647 | [currentSwipeView swipeViewAnimationFromRight:self.swipeOffset<0 ? YES : NO effect:t cellHeight:CELL_HEIGHT];
648 | }
649 | }
650 | }
651 |
652 | #pragma mark -- expand
653 |
654 | - (void)expandToOffset:(CGFloat)offset
655 | {
656 |
657 | }
658 |
659 | #pragma mark -- 懒加载
660 |
661 | - (NSArray *)leftSwipeButtons
662 | {
663 | if(!_leftSwipeButtons)
664 | {
665 | _leftSwipeButtons = [NSArray array];
666 | }
667 | return _leftSwipeButtons;
668 | }
669 |
670 | - (NSArray *)rightSwipeButtons
671 | {
672 | if(!_rightSwipeButtons)
673 | {
674 | _rightSwipeButtons = [NSArray array];
675 | }
676 | return _rightSwipeButtons;
677 | }
678 |
679 | - (NSMutableSet *)perviusHiddenViewSet
680 | {
681 | if(!_perviusHiddenViewSet)
682 | {
683 | _perviusHiddenViewSet = [NSMutableSet set];
684 | }
685 | return _perviusHiddenViewSet;
686 | }
687 |
688 | @end
689 |
--------------------------------------------------------------------------------