├── demo.gif
├── .DS_Store
├── TableViewDemo
├── .DS_Store
├── TableViewDemo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── file_folder.imageset
│ │ │ ├── file_folder@2x.png
│ │ │ └── Contents.json
│ │ ├── file_zipped.imageset
│ │ │ ├── file_zipped@2x.png
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── main.m
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── AppDelegate.m
│ └── ViewController.m
└── TableViewDemo.xcodeproj
│ ├── xcuserdata
│ ├── gzc.xcuserdatad
│ │ ├── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ └── halo.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ ├── gzc.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ │ └── halo.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
└── README.md
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/demo.gif
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/.DS_Store
--------------------------------------------------------------------------------
/TableViewDemo/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/TableViewDemo/.DS_Store
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/xcuserdata/gzc.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Assets.xcassets/file_folder.imageset/file_folder@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/TableViewDemo/TableViewDemo/Assets.xcassets/file_folder.imageset/file_folder@2x.png
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Assets.xcassets/file_zipped.imageset/file_zipped@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/TableViewDemo/TableViewDemo/Assets.xcassets/file_zipped.imageset/file_zipped@2x.png
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/project.xcworkspace/xcuserdata/gzc.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/TableViewDemo/TableViewDemo.xcodeproj/project.xcworkspace/xcuserdata/gzc.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/project.xcworkspace/xcuserdata/halo.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WuOtto/TableViewDemo/HEAD/TableViewDemo/TableViewDemo.xcodeproj/project.xcworkspace/xcuserdata/halo.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // TableViewDemo
4 | //
5 | // Created by Otto on 2018/12/22.
6 | // Copyright © 2018年 Otto. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // TableViewDemo
4 | //
5 | // Created by Otto on 2018/12/22.
6 | // Copyright © 2018年 Otto. 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 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // TableViewDemo
4 | //
5 | // Created by Otto on 2018/12/22.
6 | // Copyright © 2018年 Otto. 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 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Assets.xcassets/file_folder.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "file_folder@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 | }
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Assets.xcassets/file_zipped.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "file_zipped@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 | }
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/xcuserdata/gzc.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | TableViewDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/xcuserdata/halo.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | TableViewDemo.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/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 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/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 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // TableViewDemo
4 | //
5 | // Created by Otto on 2018/12/22.
6 | // Copyright © 2018年 Otto. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "ViewController.h"
11 |
12 | @interface AppDelegate ()
13 |
14 | @end
15 |
16 | @implementation AppDelegate
17 |
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
20 | // Override point for customization after application launch.
21 |
22 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[ViewController alloc] init]];
23 | self.window.rootViewController = nav;
24 |
25 | return YES;
26 | }
27 |
28 |
29 | - (void)applicationWillResignActive:(UIApplication *)application {
30 | // 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.
31 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
32 | }
33 |
34 |
35 | - (void)applicationDidEnterBackground:(UIApplication *)application {
36 | // 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.
37 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
38 | }
39 |
40 |
41 | - (void)applicationWillEnterForeground:(UIApplication *)application {
42 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
43 | }
44 |
45 |
46 | - (void)applicationDidBecomeActive:(UIApplication *)application {
47 | // 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.
48 | }
49 |
50 |
51 | - (void)applicationWillTerminate:(UIApplication *)application {
52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
53 | }
54 |
55 |
56 | @end
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## TableViewDemo
2 | 1. 介绍**微信左滑删除的效果实现**
3 | 2. 介绍TableViewCell的常用样式及多选操作
4 |
5 | 效果图(**因为效果图是在模拟器上录的,所以第二次的时候确认删除的动画会有点异常,在真机上不会出现这种问题**)
6 |
7 | 
8 |
9 | ## 微信左滑删除的效果实现
10 | ### 原理
11 | iOS11推出的新api帮助开发者更方便的实现左滑的菜单效果,通过这个方法可以定义左滑的菜单和对应的点击事件
12 |
13 | ```
14 | - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath{
15 |
16 | }
17 | ```
18 |
19 | 当我们在创建一个action的时候,是这样创建的:
20 |
21 | ```
22 | UIContextualAction *moreAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"更多" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
23 |
24 |
25 | }];
26 | ```
27 |
28 | 其中有一个参数block,这个block也是实现此效果最重要的部分,这个block它有3个参数:
29 |
30 | > action: 这个指的就是我们创建的action对象
31 |
32 | > sourceView: 这个view非常重要,当action的title不为空时,sourceView是一个UILabel, 当action的title为空时,sourceView是一个UIButton(实际上是UISwipeActionStandardButton)
33 |
34 | > completionHandler: 这个参数是一个block,这个block是一个细节了,不知道大家有没有注意到,在iOS11之前,只要你点击了左滑出现的任意一个按钮,cell都会退出编辑,也就是左滑按钮会消失,iOS11之后不会了,如果你想实现这个效果,只要回调一下`completionHandler`即可,参数是一个`BOOL`值,传YES和NO的区别是:传NO,系统只退出编辑,传YES ,如果是删除样式,系统会自动为你做删除cell操作。
35 |
36 |
37 | ### 实现
38 | 思路是,**创建一个Label,点击删除按钮时,将该Label加在sourceView最顶层父view上,即加在前面提到过的UISwipeActionPullView上,同时以UIView动画改变这个Label的frame**
39 |
40 | ```
41 | - (UILabel *)confirmDeleteLabel{
42 | if (!_confirmDeleteLabel) {
43 | UILabel *label = [[UILabel alloc] init];
44 | label.text = @"确认删除";
45 | label.textAlignment = NSTextAlignmentCenter;
46 | label.textColor = [UIColor whiteColor];
47 | label.backgroundColor = [UIColor colorWithRed:250/255.0 green:62/255.0 blue:56/255.0 alpha:1];
48 | label.userInteractionEnabled = YES;
49 | _confirmDeleteLabel = label;
50 | }
51 | return _confirmDeleteLabel;
52 | }
53 |
54 | //API_AVAILABLE(ios(11.0))
55 | - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath{
56 | UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"删除" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
57 |
58 | // 核心代码
59 | UIView *rootView = nil; // 这个rootView指的是UISwipeActionPullView,最上层的父view
60 | if ([sourceView isKindOfClass:[UILabel class]]) {
61 | rootView = sourceView.superview.superview;
62 | self.confirmDeleteLabel.font = ((UILabel *)sourceView).font;
63 | }
64 | self.confirmDeleteLabel.frame = CGRectMake(sourceView.bounds.size.width, 0, sourceView.bounds.size.width, sourceView.bounds.size.height);
65 | [sourceView.superview.superview addSubview:self.confirmDeleteLabel];
66 |
67 | [UIView animateWithDuration:0.7 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
68 | CGRect labelFrame = self.confirmDeleteLabel.frame;
69 | labelFrame.origin.x = 0;
70 | labelFrame.size.width = rootView.bounds.size.width;
71 | self.confirmDeleteLabel.frame = labelFrame;
72 | } completion:^(BOOL finished) {
73 |
74 | }];
75 |
76 | }];
77 |
78 | UIContextualAction *moreAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"更多" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
79 |
80 | }];
81 |
82 | UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction,moreAction]];
83 | config.performsFirstActionWithFullSwipe = NO;
84 | return config;
85 | }
86 | ```
87 |
88 | 到这一步,动画效果已经实现,但是令人头疼的是点击事件的处理,给`确认删除Label`加手势或者换成`UIButton`都不会触发点击事件。虽然我们定义的`更多`和`删除`已经被确认删除遮挡,但是点击相应位置,执行的还是我们定义action时定义的事件。所以这里的解决方案是,当`确认删除Label`显示出来的时候,点击`更多`也执行`删除操作`。实现如下:
89 |
90 | ```
91 | - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath{
92 | UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"删除" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
93 |
94 | if (self.confirmDeleteLabel.superview) {
95 | [self.dataArr removeObjectAtIndex:indexPath.row];
96 | [self.mainTableView reloadData];
97 | } else {
98 | NSLog(@"显示确认删除Label");
99 | // 核心代码
100 | UIView *rootView = nil; // 这个rootView指的是UISwipeActionPullView,最上层的父view
101 | if ([sourceView isKindOfClass:[UILabel class]]) {
102 | rootView = sourceView.superview.superview;
103 | self.confirmDeleteLabel.font = ((UILabel *)sourceView).font;
104 | }
105 | self.confirmDeleteLabel.frame = CGRectMake(sourceView.bounds.size.width, 0, sourceView.bounds.size.width, sourceView.bounds.size.height);
106 | [sourceView.superview.superview addSubview:self.confirmDeleteLabel];
107 |
108 | [UIView animateWithDuration:0.7 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
109 | CGRect labelFrame = self.confirmDeleteLabel.frame;
110 | labelFrame.origin.x = 0;
111 | labelFrame.size.width = rootView.bounds.size.width;
112 | self.confirmDeleteLabel.frame = labelFrame;
113 | } completion:^(BOOL finished) {
114 |
115 | }];
116 | }
117 |
118 | }];
119 |
120 | UIContextualAction *moreAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"更多" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
121 |
122 | if (self.confirmDeleteLabel.superview) {
123 | [self.dataArr removeObjectAtIndex:indexPath.row];
124 | [self.mainTableView reloadData];
125 | } else {
126 | NSLog(@"更多");
127 | }
128 |
129 | }];
130 |
131 | UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction,moreAction]];
132 | config.performsFirstActionWithFullSwipe = NO;
133 | return config;
134 | }
135 | ```
136 |
137 | ### 细节调整
138 | + 左滑的效果有一个细节是,当你的手指左滑cell,一直往左滑动,最右边的删除按钮会变长,于是就导致`确认删除`的label不会展示出来。所以我们要设置`UISwipeActionsConfiguration`的属性`performsFirstActionWithFullSwipe`为`NO`
139 |
140 | ```
141 | UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction,moreAction]];
142 | config.performsFirstActionWithFullSwipe = NO;
143 | ```
144 |
145 | + 实现当左滑按钮已经出现时,再次左滑则移除我们添加的`确认删除Label`,这里我们采用的是获取tableView的左滑手势,然后给该手势增加一个方法如下:
146 |
147 | ```
148 | for (UIGestureRecognizer *ges in self.mainTableView.gestureRecognizers) {
149 | if ([ges isKindOfClass:NSClassFromString(@"_UISwipeActionPanGestureRecognizer")]) {
150 | [ges addTarget:self action:@selector(_swipeRecognizerDidRecognize:)];
151 | }
152 | }
153 |
154 | - (void)_swipeRecognizerDidRecognize:(UISwipeGestureRecognizer *)swipe{
155 | if (_confirmDeleteLabel.superview) {
156 | [_confirmDeleteLabel removeFromSuperview];
157 | _confirmDeleteLabel = nil;
158 | }
159 | }
160 | ```
161 |
162 | + 修改左滑删除按钮的文字颜色和字体大小,系统虽然没有提供接口,但是我们可以在代理方法里面获取到这个控件,然后对其进行个性化定制。如下:
163 |
164 | ```
165 | // 在这个代理方法里,可以获取左滑按钮,进而修改其文字颜色,大小等
166 | - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
167 | NSLog(@"将要开始编辑cell");
168 |
169 | for (UIView *subView in tableView.subviews) {
170 | if ([subView isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]) {
171 | for (UIView *childView in subView.subviews) {
172 | if ([childView isKindOfClass:NSClassFromString(@"UISwipeActionStandardButton")]) {
173 | UIButton *button = (UIButton *)childView;
174 | button.titleLabel.font = [UIFont systemFontOfSize:18];
175 | }
176 | }
177 | }
178 | }
179 |
180 | }
181 | ```
182 |
183 | ## TableView的常用样式及多选操作
184 | ### 实现cell的多选操作
185 | ```
186 | //开始选择
187 | [self.mainTableView setEditing:YES animated:YES];
188 |
189 | //结束选择
190 | [self.mainTableView setEditing:NO animated:YES];
191 |
192 | -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
193 | return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
194 | }
195 |
196 | //选中和取消选中
197 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
198 | }
199 | - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
200 | }
201 | ```
202 |
203 | ### cell右边的箭头和详情按钮
204 | ```
205 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
206 | cell.accessoryType = UITableViewCellAccessoryDetailButton;
207 |
208 | //UITableViewCellAccessoryDetailButton的点击事件
209 | - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
210 | }
211 | ```
212 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // TableViewDemo
4 | //
5 | // Created by Otto on 2018/12/22.
6 | // Copyright © 2018年 Otto. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 |
11 | @interface ViewController ()
12 |
13 | @property (nonatomic, strong) UITableView *mainTableView;
14 |
15 | @property (nonatomic, strong) NSMutableArray *dataArr;
16 |
17 | @property (nonatomic, strong) UILabel *confirmDeleteLabel;
18 |
19 | @property (nonatomic, strong) UIBarButtonItem *rightButton;
20 |
21 | @property (nonatomic, strong) NSMutableArray *selectedArr;
22 |
23 | @end
24 |
25 | @implementation ViewController
26 |
27 | - (UILabel *)confirmDeleteLabel{
28 | if (!_confirmDeleteLabel) {
29 | UILabel *label = [[UILabel alloc] init];
30 | label.text = @"确认删除";
31 | label.textAlignment = NSTextAlignmentCenter;
32 | label.textColor = [UIColor whiteColor];
33 | label.backgroundColor = [UIColor colorWithRed:250/255.0 green:62/255.0 blue:56/255.0 alpha:1];
34 | label.userInteractionEnabled = YES;
35 | _confirmDeleteLabel = label;
36 | }
37 | return _confirmDeleteLabel;
38 | }
39 |
40 | - (void)viewDidLoad {
41 | [super viewDidLoad];
42 |
43 | self.navigationItem.title = @"文件管理";
44 |
45 | self.dataArr = [NSMutableArray arrayWithObjects:@"图片",@"视频",@"文档",@"音频",@"压缩文件",@"其他",@"TableViewDemo.zip", nil];
46 |
47 | self.mainTableView = [[UITableView alloc] initWithFrame:self.view.bounds];
48 | self.mainTableView.delegate = self;
49 | self.mainTableView.dataSource = self;
50 | [self.view addSubview:self.mainTableView];
51 |
52 | self.mainTableView.tableFooterView = [UIView new];
53 |
54 | for (UIGestureRecognizer *ges in self.mainTableView.gestureRecognizers) {
55 | if ([ges isKindOfClass:NSClassFromString(@"_UISwipeActionPanGestureRecognizer")]) {
56 | [ges addTarget:self action:@selector(_swipeRecognizerDidRecognize:)];
57 | }
58 | }
59 |
60 |
61 | self.rightButton = [[UIBarButtonItem alloc] initWithTitle:@"选择" style:UIBarButtonItemStylePlain target:self action:@selector(beginToSelectFile:)];
62 | self.navigationItem.rightBarButtonItem = self.rightButton;
63 |
64 | }
65 |
66 | - (void)beginToSelectFile:(UIBarButtonItem *)rightItem{
67 | NSString *itemTitle = rightItem.title;
68 |
69 | if ([itemTitle isEqualToString:@"选择"]) {
70 | self.selectedArr = [NSMutableArray array];
71 | [self.mainTableView setEditing:YES animated:YES];
72 | rightItem.title = @"完成";
73 | [self addNavLeftItemWithTitle:@"全选" andSeloctor:@selector(setSelectAllFile)];
74 | }else if ([itemTitle isEqualToString:@"完成"]){
75 | [self.mainTableView setEditing:NO animated:YES];
76 | rightItem.title = @"选择";
77 | self.navigationItem.leftBarButtonItem = nil;
78 | }
79 | }
80 |
81 | - (void)addNavLeftItemWithTitle:(NSString *)title andSeloctor:(SEL)selector{
82 | UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithTitle:title style:UIBarButtonItemStylePlain target:self action:selector];
83 | self.navigationItem.leftBarButtonItem = leftItem;
84 | }
85 |
86 | - (void)setSelectAllFile{
87 | [self addNavLeftItemWithTitle:@"取消全选" andSeloctor:@selector(setCancelSelectAllFile)];
88 |
89 | for (int i = 0; i< self.dataArr.count; i++) {
90 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
91 | [self.mainTableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionTop];
92 | }
93 |
94 | if (self.selectedArr.count >0) {
95 | [self.selectedArr removeAllObjects];
96 | }
97 | [self.selectedArr addObjectsFromArray:self.dataArr];
98 |
99 | }
100 |
101 | - (void)setCancelSelectAllFile{
102 |
103 | for (int i = 0; i< self.dataArr.count; i++) {
104 | NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
105 | [self.mainTableView deselectRowAtIndexPath:indexPath animated:NO];
106 | }
107 | [self.selectedArr removeAllObjects];
108 | [self addNavLeftItemWithTitle:@"全选" andSeloctor:@selector(setSelectAllFile)];
109 | }
110 |
111 | - (void)_swipeRecognizerDidRecognize:(UISwipeGestureRecognizer *)swipe{
112 | if (_confirmDeleteLabel.superview) {
113 | [_confirmDeleteLabel removeFromSuperview];
114 | _confirmDeleteLabel = nil;
115 | }
116 | }
117 |
118 | #pragma mark - UITableViewDelegate
119 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
120 | return self.dataArr.count;
121 | }
122 |
123 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
124 | return 60;
125 | }
126 |
127 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
128 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
129 | if (!cell) {
130 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"UITableViewCell"];
131 | }
132 | cell.textLabel.text = self.dataArr[indexPath.row];
133 | if (indexPath.row == self.dataArr.count - 1) {
134 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%u MB",arc4random()%20];
135 | cell.accessoryType = UITableViewCellAccessoryDetailButton;
136 | cell.imageView.image = [UIImage imageNamed:@"file_zipped"];
137 | }else{
138 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%u项",arc4random()%20];
139 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
140 | cell.imageView.image = [UIImage imageNamed:@"file_folder"];
141 | }
142 |
143 | return cell;
144 | }
145 |
146 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
147 |
148 | if ([self.rightButton.title isEqualToString:@"完成"]) {
149 | [self.selectedArr addObject:self.dataArr[indexPath.row]];
150 | } else if ([self.rightButton.title isEqualToString:@"选择"]){
151 | [tableView deselectRowAtIndexPath:indexPath animated:YES];
152 | }
153 | }
154 |
155 | - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
156 | if ([self.rightButton.title isEqualToString:@"完成"]) {
157 | [self.selectedArr removeObject:self.dataArr[indexPath.row]];
158 | if (self.selectedArr.count == 0) {
159 |
160 | }else{
161 |
162 | }
163 | } else if ([self.rightButton.title isEqualToString:@"选择"]) {
164 |
165 | }
166 |
167 | }
168 |
169 | -(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
170 | return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
171 | }
172 |
173 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
174 | return YES;
175 | }
176 |
177 | //API_AVAILABLE(ios(11.0))
178 | - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath{
179 | UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"删除" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
180 |
181 | if (self.confirmDeleteLabel.superview) {
182 | [self.dataArr removeObjectAtIndex:indexPath.row];
183 | [self.mainTableView reloadData];
184 | } else {
185 | NSLog(@"显示确认删除Label");
186 | // 核心代码
187 | UIView *rootView = nil; // 这个rootView指的是UISwipeActionPullView,最上层的父view
188 | if ([sourceView isKindOfClass:[UILabel class]]) {
189 | rootView = sourceView.superview.superview;
190 | self.confirmDeleteLabel.font = ((UILabel *)sourceView).font;
191 | }
192 | self.confirmDeleteLabel.frame = CGRectMake(sourceView.bounds.size.width, 0, sourceView.bounds.size.width, sourceView.bounds.size.height);
193 | [sourceView.superview.superview addSubview:self.confirmDeleteLabel];
194 |
195 | [UIView animateWithDuration:0.7 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
196 | CGRect labelFrame = self.confirmDeleteLabel.frame;
197 | labelFrame.origin.x = 0;
198 | labelFrame.size.width = rootView.bounds.size.width;
199 | self.confirmDeleteLabel.frame = labelFrame;
200 | } completion:^(BOOL finished) {
201 |
202 | }];
203 | }
204 |
205 | }];
206 |
207 | UIContextualAction *moreAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"更多" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
208 |
209 | if (self.confirmDeleteLabel.superview) {
210 | [self.dataArr removeObjectAtIndex:indexPath.row];
211 | [self.mainTableView reloadData];
212 | } else {
213 | NSLog(@"更多");
214 | }
215 |
216 | }];
217 |
218 | UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction,moreAction]];
219 | config.performsFirstActionWithFullSwipe = NO;
220 | return config;
221 | }
222 |
223 | - (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath{
224 | return nil;
225 | }
226 |
227 | // 在这个代理方法里,可以获取左滑按钮,进而修改其文字颜色,大小等
228 | - (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
229 | NSLog(@"将要开始编辑cell");
230 |
231 | for (UIView *subView in tableView.subviews) {
232 | if ([subView isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]) {
233 | for (UIView *childView in subView.subviews) {
234 | if ([childView isKindOfClass:NSClassFromString(@"UISwipeActionStandardButton")]) {
235 | UIButton *button = (UIButton *)childView;
236 | button.titleLabel.font = [UIFont systemFontOfSize:18];
237 | }
238 | }
239 | }
240 | }
241 |
242 | }
243 |
244 | - (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {
245 | NSLog(@"已经结束编辑cell");
246 | }
247 |
248 | - (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
249 | [self showAlertWithTitle:@"点击了详情按钮"];
250 | }
251 |
252 | - (void)showAlertWithTitle:(NSString *)title{
253 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:title preferredStyle:UIAlertControllerStyleAlert];
254 | UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
255 |
256 | }];
257 | [alert addAction:action];
258 | [self presentViewController:alert animated:YES completion:nil];
259 | }
260 |
261 | - (void)didReceiveMemoryWarning {
262 | [super didReceiveMemoryWarning];
263 | // Dispose of any resources that can be recreated.
264 | }
265 |
266 |
267 | @end
268 |
--------------------------------------------------------------------------------
/TableViewDemo/TableViewDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2DB7665921CDE6D60089950C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DB7665821CDE6D60089950C /* AppDelegate.m */; };
11 | 2DB7665C21CDE6D60089950C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DB7665B21CDE6D60089950C /* ViewController.m */; };
12 | 2DB7665F21CDE6D60089950C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2DB7665D21CDE6D60089950C /* Main.storyboard */; };
13 | 2DB7666121CDE6D60089950C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2DB7666021CDE6D60089950C /* Assets.xcassets */; };
14 | 2DB7666421CDE6D60089950C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2DB7666221CDE6D60089950C /* LaunchScreen.storyboard */; };
15 | 2DB7666721CDE6D60089950C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DB7666621CDE6D60089950C /* main.m */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 2DB7665421CDE6D60089950C /* TableViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TableViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 2DB7665721CDE6D60089950C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
21 | 2DB7665821CDE6D60089950C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
22 | 2DB7665A21CDE6D60089950C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
23 | 2DB7665B21CDE6D60089950C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
24 | 2DB7665E21CDE6D60089950C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | 2DB7666021CDE6D60089950C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
26 | 2DB7666321CDE6D60089950C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
27 | 2DB7666521CDE6D60089950C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | 2DB7666621CDE6D60089950C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 2DB7665121CDE6D60089950C /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 2DB7664B21CDE6D60089950C = {
43 | isa = PBXGroup;
44 | children = (
45 | 2DB7665621CDE6D60089950C /* TableViewDemo */,
46 | 2DB7665521CDE6D60089950C /* Products */,
47 | );
48 | sourceTree = "";
49 | };
50 | 2DB7665521CDE6D60089950C /* Products */ = {
51 | isa = PBXGroup;
52 | children = (
53 | 2DB7665421CDE6D60089950C /* TableViewDemo.app */,
54 | );
55 | name = Products;
56 | sourceTree = "";
57 | };
58 | 2DB7665621CDE6D60089950C /* TableViewDemo */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 2DB7665721CDE6D60089950C /* AppDelegate.h */,
62 | 2DB7665821CDE6D60089950C /* AppDelegate.m */,
63 | 2DB7665A21CDE6D60089950C /* ViewController.h */,
64 | 2DB7665B21CDE6D60089950C /* ViewController.m */,
65 | 2DB7665D21CDE6D60089950C /* Main.storyboard */,
66 | 2DB7666021CDE6D60089950C /* Assets.xcassets */,
67 | 2DB7666221CDE6D60089950C /* LaunchScreen.storyboard */,
68 | 2DB7666521CDE6D60089950C /* Info.plist */,
69 | 2DB7666621CDE6D60089950C /* main.m */,
70 | );
71 | path = TableViewDemo;
72 | sourceTree = "";
73 | };
74 | /* End PBXGroup section */
75 |
76 | /* Begin PBXNativeTarget section */
77 | 2DB7665321CDE6D60089950C /* TableViewDemo */ = {
78 | isa = PBXNativeTarget;
79 | buildConfigurationList = 2DB7666A21CDE6D60089950C /* Build configuration list for PBXNativeTarget "TableViewDemo" */;
80 | buildPhases = (
81 | 2DB7665021CDE6D60089950C /* Sources */,
82 | 2DB7665121CDE6D60089950C /* Frameworks */,
83 | 2DB7665221CDE6D60089950C /* Resources */,
84 | );
85 | buildRules = (
86 | );
87 | dependencies = (
88 | );
89 | name = TableViewDemo;
90 | productName = TableViewDemo;
91 | productReference = 2DB7665421CDE6D60089950C /* TableViewDemo.app */;
92 | productType = "com.apple.product-type.application";
93 | };
94 | /* End PBXNativeTarget section */
95 |
96 | /* Begin PBXProject section */
97 | 2DB7664C21CDE6D60089950C /* Project object */ = {
98 | isa = PBXProject;
99 | attributes = {
100 | LastUpgradeCheck = 0920;
101 | ORGANIZATIONNAME = Otto;
102 | TargetAttributes = {
103 | 2DB7665321CDE6D60089950C = {
104 | CreatedOnToolsVersion = 9.2;
105 | ProvisioningStyle = Automatic;
106 | };
107 | };
108 | };
109 | buildConfigurationList = 2DB7664F21CDE6D60089950C /* Build configuration list for PBXProject "TableViewDemo" */;
110 | compatibilityVersion = "Xcode 8.0";
111 | developmentRegion = en;
112 | hasScannedForEncodings = 0;
113 | knownRegions = (
114 | en,
115 | Base,
116 | );
117 | mainGroup = 2DB7664B21CDE6D60089950C;
118 | productRefGroup = 2DB7665521CDE6D60089950C /* Products */;
119 | projectDirPath = "";
120 | projectRoot = "";
121 | targets = (
122 | 2DB7665321CDE6D60089950C /* TableViewDemo */,
123 | );
124 | };
125 | /* End PBXProject section */
126 |
127 | /* Begin PBXResourcesBuildPhase section */
128 | 2DB7665221CDE6D60089950C /* Resources */ = {
129 | isa = PBXResourcesBuildPhase;
130 | buildActionMask = 2147483647;
131 | files = (
132 | 2DB7666421CDE6D60089950C /* LaunchScreen.storyboard in Resources */,
133 | 2DB7666121CDE6D60089950C /* Assets.xcassets in Resources */,
134 | 2DB7665F21CDE6D60089950C /* Main.storyboard in Resources */,
135 | );
136 | runOnlyForDeploymentPostprocessing = 0;
137 | };
138 | /* End PBXResourcesBuildPhase section */
139 |
140 | /* Begin PBXSourcesBuildPhase section */
141 | 2DB7665021CDE6D60089950C /* Sources */ = {
142 | isa = PBXSourcesBuildPhase;
143 | buildActionMask = 2147483647;
144 | files = (
145 | 2DB7665C21CDE6D60089950C /* ViewController.m in Sources */,
146 | 2DB7666721CDE6D60089950C /* main.m in Sources */,
147 | 2DB7665921CDE6D60089950C /* AppDelegate.m in Sources */,
148 | );
149 | runOnlyForDeploymentPostprocessing = 0;
150 | };
151 | /* End PBXSourcesBuildPhase section */
152 |
153 | /* Begin PBXVariantGroup section */
154 | 2DB7665D21CDE6D60089950C /* Main.storyboard */ = {
155 | isa = PBXVariantGroup;
156 | children = (
157 | 2DB7665E21CDE6D60089950C /* Base */,
158 | );
159 | name = Main.storyboard;
160 | sourceTree = "";
161 | };
162 | 2DB7666221CDE6D60089950C /* LaunchScreen.storyboard */ = {
163 | isa = PBXVariantGroup;
164 | children = (
165 | 2DB7666321CDE6D60089950C /* Base */,
166 | );
167 | name = LaunchScreen.storyboard;
168 | sourceTree = "";
169 | };
170 | /* End PBXVariantGroup section */
171 |
172 | /* Begin XCBuildConfiguration section */
173 | 2DB7666821CDE6D60089950C /* Debug */ = {
174 | isa = XCBuildConfiguration;
175 | buildSettings = {
176 | ALWAYS_SEARCH_USER_PATHS = NO;
177 | CLANG_ANALYZER_NONNULL = YES;
178 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
179 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
180 | CLANG_CXX_LIBRARY = "libc++";
181 | CLANG_ENABLE_MODULES = YES;
182 | CLANG_ENABLE_OBJC_ARC = YES;
183 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
184 | CLANG_WARN_BOOL_CONVERSION = YES;
185 | CLANG_WARN_COMMA = YES;
186 | CLANG_WARN_CONSTANT_CONVERSION = YES;
187 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
188 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
189 | CLANG_WARN_EMPTY_BODY = YES;
190 | CLANG_WARN_ENUM_CONVERSION = YES;
191 | CLANG_WARN_INFINITE_RECURSION = YES;
192 | CLANG_WARN_INT_CONVERSION = YES;
193 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
194 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
195 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
196 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
197 | CLANG_WARN_STRICT_PROTOTYPES = YES;
198 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
199 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
200 | CLANG_WARN_UNREACHABLE_CODE = YES;
201 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
202 | CODE_SIGN_IDENTITY = "iPhone Developer";
203 | COPY_PHASE_STRIP = NO;
204 | DEBUG_INFORMATION_FORMAT = dwarf;
205 | ENABLE_STRICT_OBJC_MSGSEND = YES;
206 | ENABLE_TESTABILITY = YES;
207 | GCC_C_LANGUAGE_STANDARD = gnu11;
208 | GCC_DYNAMIC_NO_PIC = NO;
209 | GCC_NO_COMMON_BLOCKS = YES;
210 | GCC_OPTIMIZATION_LEVEL = 0;
211 | GCC_PREPROCESSOR_DEFINITIONS = (
212 | "DEBUG=1",
213 | "$(inherited)",
214 | );
215 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
216 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
217 | GCC_WARN_UNDECLARED_SELECTOR = YES;
218 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
219 | GCC_WARN_UNUSED_FUNCTION = YES;
220 | GCC_WARN_UNUSED_VARIABLE = YES;
221 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
222 | MTL_ENABLE_DEBUG_INFO = YES;
223 | ONLY_ACTIVE_ARCH = YES;
224 | SDKROOT = iphoneos;
225 | };
226 | name = Debug;
227 | };
228 | 2DB7666921CDE6D60089950C /* Release */ = {
229 | isa = XCBuildConfiguration;
230 | buildSettings = {
231 | ALWAYS_SEARCH_USER_PATHS = NO;
232 | CLANG_ANALYZER_NONNULL = YES;
233 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
235 | CLANG_CXX_LIBRARY = "libc++";
236 | CLANG_ENABLE_MODULES = YES;
237 | CLANG_ENABLE_OBJC_ARC = YES;
238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
239 | CLANG_WARN_BOOL_CONVERSION = YES;
240 | CLANG_WARN_COMMA = YES;
241 | CLANG_WARN_CONSTANT_CONVERSION = YES;
242 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
243 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
244 | CLANG_WARN_EMPTY_BODY = YES;
245 | CLANG_WARN_ENUM_CONVERSION = YES;
246 | CLANG_WARN_INFINITE_RECURSION = YES;
247 | CLANG_WARN_INT_CONVERSION = YES;
248 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
249 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
250 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
251 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
252 | CLANG_WARN_STRICT_PROTOTYPES = YES;
253 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
254 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
255 | CLANG_WARN_UNREACHABLE_CODE = YES;
256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
257 | CODE_SIGN_IDENTITY = "iPhone Developer";
258 | COPY_PHASE_STRIP = NO;
259 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
260 | ENABLE_NS_ASSERTIONS = NO;
261 | ENABLE_STRICT_OBJC_MSGSEND = YES;
262 | GCC_C_LANGUAGE_STANDARD = gnu11;
263 | GCC_NO_COMMON_BLOCKS = YES;
264 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
265 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
266 | GCC_WARN_UNDECLARED_SELECTOR = YES;
267 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
268 | GCC_WARN_UNUSED_FUNCTION = YES;
269 | GCC_WARN_UNUSED_VARIABLE = YES;
270 | IPHONEOS_DEPLOYMENT_TARGET = 11.2;
271 | MTL_ENABLE_DEBUG_INFO = NO;
272 | SDKROOT = iphoneos;
273 | VALIDATE_PRODUCT = YES;
274 | };
275 | name = Release;
276 | };
277 | 2DB7666B21CDE6D60089950C /* Debug */ = {
278 | isa = XCBuildConfiguration;
279 | buildSettings = {
280 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
281 | CODE_SIGN_STYLE = Automatic;
282 | DEVELOPMENT_TEAM = "";
283 | INFOPLIST_FILE = TableViewDemo/Info.plist;
284 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
285 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
286 | PRODUCT_BUNDLE_IDENTIFIER = Otto.TableViewDemo;
287 | PRODUCT_NAME = "$(TARGET_NAME)";
288 | TARGETED_DEVICE_FAMILY = "1,2";
289 | };
290 | name = Debug;
291 | };
292 | 2DB7666C21CDE6D60089950C /* Release */ = {
293 | isa = XCBuildConfiguration;
294 | buildSettings = {
295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
296 | CODE_SIGN_STYLE = Automatic;
297 | DEVELOPMENT_TEAM = "";
298 | INFOPLIST_FILE = TableViewDemo/Info.plist;
299 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
300 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
301 | PRODUCT_BUNDLE_IDENTIFIER = Otto.TableViewDemo;
302 | PRODUCT_NAME = "$(TARGET_NAME)";
303 | TARGETED_DEVICE_FAMILY = "1,2";
304 | };
305 | name = Release;
306 | };
307 | /* End XCBuildConfiguration section */
308 |
309 | /* Begin XCConfigurationList section */
310 | 2DB7664F21CDE6D60089950C /* Build configuration list for PBXProject "TableViewDemo" */ = {
311 | isa = XCConfigurationList;
312 | buildConfigurations = (
313 | 2DB7666821CDE6D60089950C /* Debug */,
314 | 2DB7666921CDE6D60089950C /* Release */,
315 | );
316 | defaultConfigurationIsVisible = 0;
317 | defaultConfigurationName = Release;
318 | };
319 | 2DB7666A21CDE6D60089950C /* Build configuration list for PBXNativeTarget "TableViewDemo" */ = {
320 | isa = XCConfigurationList;
321 | buildConfigurations = (
322 | 2DB7666B21CDE6D60089950C /* Debug */,
323 | 2DB7666C21CDE6D60089950C /* Release */,
324 | );
325 | defaultConfigurationIsVisible = 0;
326 | defaultConfigurationName = Release;
327 | };
328 | /* End XCConfigurationList section */
329 | };
330 | rootObject = 2DB7664C21CDE6D60089950C /* Project object */;
331 | }
332 |
--------------------------------------------------------------------------------