├── SwipeableTableViewCellExample
├── Assets.xcassets
│ ├── Contents.json
│ ├── delete-icon.imageset
│ │ ├── delete-icon.pdf
│ │ └── Contents.json
│ ├── later-icon.imageset
│ │ ├── later-icon.pdf
│ │ └── Contents.json
│ ├── check-icon.imageset
│ │ ├── check-icon@2x.png
│ │ ├── check-icon@3x.png
│ │ └── Contents.json
│ ├── clock-icon.imageset
│ │ ├── clock-icon@2x.png
│ │ ├── clock-icon@3x.png
│ │ └── Contents.json
│ ├── cross-icon.imageset
│ │ ├── cross-icon@2x.png
│ │ ├── cross-icon@3x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── BackgroundViewCell.swift
├── BackgroundViewSwipeableCell.swift
├── AppDelegate.swift
├── Info.plist
├── ExampleMenuViewController.swift
├── BackgroundViewExampleViewController.swift
├── StylesExampleViewController.swift
└── Base.lproj
│ └── Main.storyboard
├── Gif
└── SwipeableTableViewCellExample.gif
├── SwipeableTableViewCell.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ ├── hongxin.xcuserdatad
│ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ └── wangwei.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── xcshareddata
│ └── xcschemes
│ │ └── SwipeableTableViewCell.xcscheme
└── project.pbxproj
├── SwipeableTableViewCell.xcworkspace
├── xcuserdata
│ └── wangwei.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── contents.xcworkspacedata
├── SwipeableTableViewCellExample.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcuserdata
│ ├── hongxin.xcuserdatad
│ │ └── xcschemes
│ │ │ ├── xcschememanagement.plist
│ │ │ └── SwipeableTableViewCellExample.xcscheme
│ └── wangwei.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── SwipeableTableViewCellExample.xcscheme
└── project.pbxproj
├── SwipeableTableViewCell
├── Supporting Files
│ └── Info.plist
├── SwipeableCellAction.swift
├── SwipeableCellActionsView.swift
└── SwipeableTableViewCell.swift
├── LICENSE.md
├── .gitignore
└── README.md
/SwipeableTableViewCellExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Gif/SwipeableTableViewCellExample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/Gif/SwipeableTableViewCellExample.gif
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/delete-icon.imageset/delete-icon.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/delete-icon.imageset/delete-icon.pdf
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/later-icon.imageset/later-icon.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/later-icon.imageset/later-icon.pdf
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/check-icon.imageset/check-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/check-icon.imageset/check-icon@2x.png
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/check-icon.imageset/check-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/check-icon.imageset/check-icon@3x.png
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/clock-icon.imageset/clock-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/clock-icon.imageset/clock-icon@2x.png
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/clock-icon.imageset/clock-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/clock-icon.imageset/clock-icon@3x.png
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/cross-icon.imageset/cross-icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/cross-icon.imageset/cross-icon@2x.png
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/cross-icon.imageset/cross-icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCellExample/Assets.xcassets/cross-icon.imageset/cross-icon@3x.png
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcworkspace/xcuserdata/wangwei.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alibaba-archive/SwipeableTableViewCell/HEAD/SwipeableTableViewCell.xcworkspace/xcuserdata/wangwei.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/delete-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "delete-icon.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/later-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "later-icon.pdf"
6 | }
7 | ],
8 | "info" : {
9 | "version" : 1,
10 | "author" : "xcode"
11 | }
12 | }
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/check-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "check-icon@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "check-icon@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/clock-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "clock-icon@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "clock-icon@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/Assets.xcassets/cross-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "cross-icon@2x.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "cross-icon@3x.png",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwipeableTableViewCell.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D3C6AD571C1FBE9600580522
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwipeableTableViewCell.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D3C6AD571C1FBE9600580522
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwipeableTableViewCellExample.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D3C6AD6B1C1FBED500580522
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SwipeableTableViewCellExample.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | D3C6AD6B1C1FBED500580522
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/BackgroundViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BackgroundViewCell.swift
3 | // SwipeableTableViewCellExample
4 | //
5 | // Created by 洪鑫 on 16/6/5.
6 | // Copyright © 2016年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | let kCellSelectedColor = UIColor(red:3 / 255.0, green:169 / 255.0, blue:244 / 255.0, alpha:1)
12 | let kBackgroundViewCellID = "BackgroundViewCell"
13 |
14 | class BackgroundViewCell: UITableViewCell {
15 | @IBOutlet weak var titleLabel: UILabel!
16 |
17 | override func awakeFromNib() {
18 | super.awakeFromNib()
19 | selectedBackgroundView = UIView()
20 | selectedBackgroundView?.backgroundColor = kCellSelectedColor
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/BackgroundViewSwipeableCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeableCell.swift
3 | // SwipeableTableViewCellExample
4 | //
5 | // Created by 洪鑫 on 16/6/5.
6 | // Copyright © 2016年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwipeableTableViewCell
11 |
12 | let kBackgroundViewSwipeableCellID = "BackgroundViewSwipeableCell"
13 |
14 | class BackgroundViewSwipeableCell: SwipeableTableViewCell {
15 | @IBOutlet weak var titleLabel: UILabel!
16 |
17 | override func awakeFromNib() {
18 | super.awakeFromNib()
19 | selectedBackgroundView = UIView()
20 | selectedBackgroundView?.backgroundColor = kCellSelectedColor
21 | }
22 |
23 | @IBAction func buttonTapped(_ sender: UIButton) {
24 | print("OK Tapped!")
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell/Supporting Files/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 | FMWK
17 | CFBundleShortVersionString
18 | 0.4.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell/SwipeableCellAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeableCellAction.swift
3 | // SwipeableTableViewCell
4 | //
5 | // Created by 洪鑫 on 15/12/15.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | let kSwipeableCellActionDefaultWidth: CGFloat = 90
12 | let kSwipeableCellActionDefaultVerticalSpace: CGFloat = 6
13 |
14 | public struct SwipeableCellAction {
15 | public var title: NSAttributedString?
16 | public var image: UIImage?
17 | public var backgroundColor: UIColor?
18 | public var action: () -> ()
19 | public var width: CGFloat = kSwipeableCellActionDefaultWidth
20 | public var verticalSpace: CGFloat = kSwipeableCellActionDefaultVerticalSpace
21 |
22 | public init(title: NSAttributedString?, image: UIImage?, backgroundColor: UIColor, action: @escaping () -> ()) {
23 | self.title = title
24 | self.image = image
25 | self.backgroundColor = backgroundColor
26 | self.action = action
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SwipeableTableViewCellExample
4 | //
5 | // Created by 洪鑫 on 15/12/15.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 | var window: UIWindow?
14 |
15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
16 | return true
17 | }
18 |
19 | func applicationWillResignActive(_ application: UIApplication) {
20 |
21 | }
22 |
23 | func applicationDidEnterBackground(_ application: UIApplication) {
24 |
25 | }
26 |
27 | func applicationWillEnterForeground(_ application: UIApplication) {
28 |
29 | }
30 |
31 | func applicationDidBecomeActive(_ application: UIApplication) {
32 |
33 | }
34 |
35 | func applicationWillTerminate(_ application: UIApplication) {
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Teambition
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 | Carthage/
9 |
10 | ## Various settings
11 | *.pbxuser
12 | !default.pbxuser
13 | *.mode1v3
14 | !default.mode1v3
15 | *.mode2v3
16 | !default.mode2v3
17 | *.perspectivev3
18 | !default.perspectivev3
19 | xcuserdata/
20 |
21 | ## Other
22 | *.moved-aside
23 | *.xccheckout
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | # Packages/
40 | # Package.pins
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/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 | 0.4.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 14
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 | UIInterfaceOrientationPortraitUpsideDown
39 |
40 | UISupportedInterfaceOrientations~ipad
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationPortraitUpsideDown
44 | UIInterfaceOrientationLandscapeLeft
45 | UIInterfaceOrientationLandscapeRight
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/ExampleMenuViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExampleMenuViewController.swift
3 | // SwipeableTableViewCellExample
4 | //
5 | // Created by 洪鑫 on 16/6/5.
6 | // Copyright © 2016年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ExampleMenuViewController: UITableViewController {
12 | // MARK: - Life cycle
13 | override func viewDidLoad() {
14 | super.viewDidLoad()
15 | navigationItem.title = "SwipeableTableViewCell"
16 | tableView.separatorColor = UIColor(white: 0.1, alpha: 0.1)
17 | }
18 |
19 | // MARK: - Table view data source and delegate
20 | override func numberOfSections(in tableView: UITableView) -> Int {
21 | return 1
22 | }
23 |
24 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
25 | return 2
26 | }
27 |
28 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
29 | return 70
30 | }
31 |
32 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
33 | var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
34 | if cell == nil {
35 | cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
36 | }
37 | switch indexPath.row {
38 | case 0:
39 | cell?.textLabel?.text = "Styles Example"
40 | case 1:
41 | cell?.textLabel?.text = "BackgroundView Example"
42 | default:
43 | break
44 | }
45 | return cell!
46 | }
47 |
48 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
49 | switch indexPath.row {
50 | case 0:
51 | performSegue(withIdentifier: "ShowStylesExampleViewController", sender: self)
52 | case 1:
53 | performSegue(withIdentifier: "ShowBackgroundViewExampleViewController", sender: self)
54 | default:
55 | break
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/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 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SwipeableTableViewCell
2 | SwipeableTableViewCell is a quite easy-to-use UITableViewCell subclass which allows you to add multiple highly customizable swipe actions.
3 |
4 | 
5 |
6 | ## How To Get Started
7 | ### Carthage
8 | Specify "SwipeableTableViewCell" in your ```Cartfile```:
9 | ```ogdl
10 | github "teambition/SwipeableTableViewCell"
11 | ```
12 |
13 | ### Usage
14 | #### 1. TableViewController
15 | Import "SwipeableTableViewCell":
16 | ```swift
17 | import SwipeableTableViewCell
18 | ```
19 | Configure cell in the data source like this:
20 | ```swift
21 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
22 | var cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as? SwipeableTableViewCell
23 | if cell == nil {
24 | cell = SwipeableTableViewCell(style: .default, reuseIdentifier: "Cell")
25 | }
26 |
27 | // assign delegate if needed
28 | cell!.delegate = self
29 |
30 | // configure cell swipe actions
31 | let deleteTitle = NSAttributedString(string: "删除", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15)])
32 | var deleteAction = SwipeableCellAction(title: deleteTitle, image: UIImage(named: "delete-icon"), backgroundColor: UIColor.red) { _ in
33 | // do something when "deleteAction" is selected
34 | }
35 | let laterTitle = NSAttributedString(string: "稍后处理", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15)])
36 | var laterAction = SwipeableCellAction(title: laterTitle, image: UIImage(named: "later-icon"), backgroundColor: UIColor.blue) { _ in
37 | // do something when "laterAction" is selected
38 | }
39 | deleteAction.width = 100
40 | deleteAction.verticalSpace = 6
41 | laterAction.width = 100
42 | laterAction.verticalSpace = 6
43 | cell!.actions = [deleteAction, laterAction]
44 |
45 | // other configurations
46 | cell!.textLabel?.text = "Cell"
47 |
48 | return cell!
49 | }
50 | ```
51 |
52 | #### 2. Implement delegate if needed
53 | ```swift
54 | func swipeableCell(_ cell: SwipeableTableViewCell, isScrollingToState state: SwipeableCellState) {
55 | // do something
56 | }
57 |
58 | func swipeableCellSwipeEnabled(_ cell: SwipeableTableViewCell) -> Bool {
59 | // cell swipe enabled or not, default value is true
60 | }
61 |
62 | func allowMultipleCellsSwipedSimultaneously() -> Bool {
63 | // allow multiple cells swiped simultaneously or not, default value is false
64 | }
65 |
66 | func swipeableCellDidEndScroll(_ cell: SwipeableTableViewCell) {
67 | // do something
68 | }
69 | ```
70 |
71 | ## Minimum Requirement
72 | iOS 8.0
73 |
74 | ## Release Notes
75 | * [Release Notes](https://github.com/teambition/SwipeableTableViewCell/releases)
76 |
77 | ## License
78 | SwipeableTableViewCell is released under the MIT license. See [LICENSE](https://github.com/teambition/SwipeableTableViewCell/blob/master/LICENSE.md) for details.
79 |
80 | ## More Info
81 | Have a question? Please [open an issue](https://github.com/teambition/SwipeableTableViewCell/issues/new)!
82 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcodeproj/xcshareddata/xcschemes/SwipeableTableViewCell.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample.xcodeproj/xcuserdata/hongxin.xcuserdatad/xcschemes/SwipeableTableViewCellExample.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 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample.xcodeproj/xcuserdata/wangwei.xcuserdatad/xcschemes/SwipeableTableViewCellExample.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 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/BackgroundViewExampleViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BackgroundViewExampleViewController.swift
3 | // SwipeableTableViewCellExample
4 | //
5 | // Created by 洪鑫 on 16/6/5.
6 | // Copyright © 2016年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwipeableTableViewCell
11 |
12 | class BackgroundViewExampleViewController: UITableViewController {
13 | fileprivate(set) var pushEnabled = false
14 |
15 | // MARK: - Life cycle
16 | override func viewDidLoad() {
17 | super.viewDidLoad()
18 | setupUI()
19 | }
20 |
21 | // MARK: - Helper
22 | fileprivate func setupUI() {
23 | tableView.tableFooterView = UIView()
24 | let switchView: UIView = {
25 | let titleView = UIView(frame: CGRect(origin: .zero, size: CGSize(width: 150, height: 40)))
26 | titleView.backgroundColor = .clear
27 | let titleLabel = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 99, height: 40)))
28 | titleLabel.backgroundColor = .clear
29 | titleLabel.text = "Push Enabled"
30 | titleLabel.font = .systemFont(ofSize: 14)
31 | titleLabel.textColor = .red
32 | titleView.addSubview(titleLabel)
33 | let pushSwitch = UISwitch()
34 | pushSwitch.frame.origin.x = 99
35 | pushSwitch.frame.origin.y = (40 - pushSwitch.frame.height) / 2
36 | pushSwitch.isOn = false
37 | pushSwitch.addTarget(self, action: #selector(pushSwitchValueChanged(_:)), for: .valueChanged)
38 | titleView.addSubview(pushSwitch)
39 | return titleView
40 | }()
41 | navigationItem.rightBarButtonItem = UIBarButtonItem(customView: switchView)
42 |
43 | if #available(iOS 9, *) {
44 | if traitCollection.forceTouchCapability == .available {
45 | registerForPreviewing(with: self, sourceView: view)
46 | }
47 | }
48 | }
49 |
50 | @objc func pushSwitchValueChanged(_ sender: UISwitch) {
51 | pushEnabled = sender.isOn
52 | }
53 |
54 | // MARK: - Table view data source and delegate
55 | override func numberOfSections(in tableView: UITableView) -> Int {
56 | return 2
57 | }
58 |
59 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
60 | return 10
61 | }
62 |
63 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
64 | return 65
65 | }
66 |
67 | override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
68 | switch section {
69 | case 0: return "SwipeableCell with background view"
70 | case 1: return "UITableViewCell with background view"
71 | default: return nil
72 | }
73 | }
74 |
75 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
76 | if indexPath.section == 0 {
77 | let cell = tableView.dequeueReusableCell(withIdentifier: kBackgroundViewSwipeableCellID, for: indexPath) as! BackgroundViewSwipeableCell
78 | let delete = NSAttributedString(string: "删除", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15)])
79 | var deleteAction = SwipeableCellAction(title: delete, image: UIImage(named: "delete-icon"), backgroundColor: UIColor(red: 255 / 255, green: 90 / 255, blue: 29 / 255, alpha: 1)) {
80 | print("删除")
81 | }
82 | let later = NSAttributedString(string: "稍后处理", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15)])
83 | var laterAction = SwipeableCellAction(title: later, image: UIImage(named: "later-icon"), backgroundColor: UIColor(red: 3 / 255, green: 169 / 255, blue: 244 / 255, alpha: 1)) {
84 | print("稍后处理")
85 | }
86 | deleteAction.width = 100
87 | deleteAction.verticalSpace = 6
88 | laterAction.width = 100
89 | laterAction.verticalSpace = 6
90 | cell.actions = [deleteAction, laterAction]
91 | return cell
92 | } else {
93 | let cell = tableView.dequeueReusableCell(withIdentifier: kBackgroundViewCellID, for: indexPath) as! BackgroundViewCell
94 | return cell
95 | }
96 | }
97 |
98 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
99 | if pushEnabled {
100 | performSegue(withIdentifier: "PushToViewController", sender: self)
101 | tableView.deselectRow(at: indexPath, animated: true)
102 | }
103 | }
104 | }
105 |
106 | @available(iOS 9.0, *)
107 | extension BackgroundViewExampleViewController: UIViewControllerPreviewingDelegate {
108 | func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
109 | guard let indexPath = tableView.indexPathForRow(at: location), let cell = tableView.cellForRow(at: indexPath) else {
110 | return nil
111 | }
112 | let previewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController")
113 | previewController.preferredContentSize = .zero
114 | previewingContext.sourceRect = cell.frame
115 | return previewController
116 | }
117 |
118 | func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
119 | show(viewControllerToCommit, sender: self)
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell/SwipeableCellActionsView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeableCellActionsView.swift
3 | // SwipeableTableViewCell
4 | //
5 | // Created by 洪鑫 on 15/12/15.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | let kActionItemViewTag = 1000
12 |
13 | class ActionItemView: UIView {
14 | fileprivate(set) var title: NSAttributedString?
15 | fileprivate(set) var image: UIImage?
16 | fileprivate(set) var width: CGFloat = 0
17 | fileprivate(set) var verticalSpace: CGFloat = 0
18 | fileprivate(set) var index = 0
19 | fileprivate(set) var action: (()-> ())!
20 |
21 | lazy var imageView: UIImageView = {
22 | let imageView = UIImageView()
23 | imageView.contentMode = .center
24 | imageView.backgroundColor = .clear
25 | imageView.isUserInteractionEnabled = false
26 | imageView.translatesAutoresizingMaskIntoConstraints = false
27 | return imageView
28 | }()
29 | lazy var titleLabel: UILabel = {
30 | let titleLabel = UILabel()
31 | titleLabel.textAlignment = .center
32 | titleLabel.backgroundColor = .clear
33 | titleLabel.isUserInteractionEnabled = false
34 | titleLabel.translatesAutoresizingMaskIntoConstraints = false
35 | return titleLabel
36 | }()
37 |
38 | convenience init(action: SwipeableCellAction, index: Int) {
39 | self.init(frame: .zero)
40 | tag = kActionItemViewTag
41 | translatesAutoresizingMaskIntoConstraints = false
42 |
43 | backgroundColor = action.backgroundColor
44 | self.title = action.title
45 | self.image = action.image
46 | self.width = action.width
47 | self.verticalSpace = action.verticalSpace
48 | self.index = index
49 | self.action = action.action
50 |
51 | isUserInteractionEnabled = true
52 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(ActionItemView.didTapActionItemView(_:)))
53 | tapGesture.numberOfTapsRequired = 1
54 | addGestureRecognizer(tapGesture)
55 |
56 | if let image = image, let title = title {
57 | imageView.image = image
58 | titleLabel.attributedText = title
59 | let contentView = UIView()
60 | contentView.backgroundColor = .clear
61 | contentView.translatesAutoresizingMaskIntoConstraints = false
62 | contentView.isUserInteractionEnabled = false
63 | contentView.addSubview(imageView)
64 | contentView.addSubview(titleLabel)
65 | addSubview(contentView)
66 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[contentView]|", options: [], metrics: nil, views: ["contentView": contentView]))
67 | addConstraint(NSLayoutConstraint(item: contentView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
68 | addConstraint(NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: contentView, attribute: .centerX, multiplier: 1, constant: 0))
69 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[titleLabel]|", options: [], metrics: nil, views: ["titleLabel": titleLabel]))
70 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[imageView]-\(verticalSpace)-[titleLabel]|", options: [], metrics: nil, views: ["imageView": imageView, "titleLabel": titleLabel]))
71 | } else if let image = image {
72 | imageView.image = image
73 | addSubview(imageView)
74 | addConstraint(NSLayoutConstraint(item: imageView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
75 | addConstraint(NSLayoutConstraint(item: imageView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
76 | } else if let title = title {
77 | titleLabel.attributedText = title
78 | addSubview(titleLabel)
79 | addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0))
80 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[titleLabel]|", options: [], metrics: nil, views: ["titleLabel": titleLabel]))
81 | }
82 | }
83 |
84 | @objc func didTapActionItemView(_ sender: Any) {
85 | action()
86 | }
87 | }
88 |
89 | class SwipeableCellActionsView: UIView {
90 | fileprivate(set) var cell: SwipeableTableViewCell?
91 | fileprivate(set) var actionItemViews = [ActionItemView]()
92 | fileprivate var actionItemViewBackgroundColors = [UIColor]()
93 |
94 | convenience init(actions: [SwipeableCellAction]?, parentCell: SwipeableTableViewCell) {
95 | self.init(frame: .zero)
96 | translatesAutoresizingMaskIntoConstraints = false
97 | self.cell = parentCell
98 | setActions(actions)
99 | }
100 |
101 | func setActions(_ actions: [SwipeableCellAction]?) {
102 | func resetData() {
103 | for subview in subviews {
104 | if subview.tag == kActionItemViewTag {
105 | subview.removeConstraints(subview.constraints)
106 | subview.removeFromSuperview()
107 | }
108 | }
109 | actionItemViews.removeAll()
110 | }
111 | func validActions(_ actions: [SwipeableCellAction]?) -> Bool {
112 | if let actions = actions {
113 | return actions.count > 0
114 | }
115 | return false
116 | }
117 |
118 | resetData()
119 | if !validActions(actions) {
120 | return
121 | }
122 |
123 | for (index, action) in actions!.enumerated() {
124 | let actionItemView = ActionItemView(action: action, index: index)
125 | actionItemViews.append(actionItemView)
126 | }
127 | var horizontalFormat = String()
128 | var itemViews = [String: ActionItemView]()
129 | for (index, actionItemView) in actionItemViews.reversed().enumerated() {
130 | let itemViewString = "actionItemView\(index)"
131 | addSubview(actionItemView)
132 | addConstraint(NSLayoutConstraint(item: actionItemView, attribute: .width, relatedBy: .equal, toItem: .none, attribute: .notAnAttribute, multiplier: 1, constant: actionItemView.width))
133 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[\(itemViewString)]|", options: [], metrics: nil, views: [itemViewString: actionItemView]))
134 | horizontalFormat += "[\(itemViewString)]"
135 | itemViews.updateValue(actionItemView, forKey: itemViewString)
136 | }
137 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|\(horizontalFormat)|", options: [], metrics: nil, views: itemViews))
138 | }
139 |
140 | func pushBackgroundColors() {
141 | actionItemViewBackgroundColors.removeAll()
142 | for actionItemView in actionItemViews {
143 | actionItemViewBackgroundColors.append(actionItemView.backgroundColor!)
144 | }
145 | }
146 |
147 | func popBackgroundColors() {
148 | for (index, color) in actionItemViewBackgroundColors.enumerated() {
149 | let actionItemView = actionItemViews[index]
150 | actionItemView.backgroundColor = color
151 | }
152 | actionItemViewBackgroundColors.removeAll()
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/StylesExampleViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StylesExampleViewController.swift
3 | // SwipeableTableViewCellExample
4 | //
5 | // Created by 洪鑫 on 15/12/15.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwipeableTableViewCell
11 |
12 | let kCellID = "SwipeableTableViewCell"
13 | let kCustomCellID = "CustomSwipeableTableViewCell"
14 |
15 | class StylesExampleViewController: UITableViewController, SwipeableTableViewCellDelegate {
16 | // MARK: - View life cycle
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 | setupUI()
20 | }
21 |
22 | // MARK: - Helper
23 | fileprivate func setupUI() {
24 | navigationItem.title = "Styles"
25 | tableView.separatorColor = UIColor(white: 0.1, alpha: 0.1)
26 | }
27 |
28 | fileprivate func showAlert(_ message: String, dismissHandler: @escaping () -> ()) {
29 | let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
30 | let cancelAction = UIAlertAction(title: "OK", style: .cancel) { _ in
31 | dismissHandler()
32 | }
33 | alert.addAction(cancelAction)
34 | present(alert, animated: true, completion: nil)
35 | }
36 |
37 | // MARK: - TableView data source and delegate
38 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
39 | return 70
40 | }
41 |
42 | override func numberOfSections(in tableView: UITableView) -> Int {
43 | return 1
44 | }
45 |
46 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
47 | return 75
48 | }
49 |
50 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
51 | if indexPath.row % 7 == 5 {
52 | let cell = tableView.dequeueReusableCell(withIdentifier: kCustomCellID, for: indexPath) as! SwipeableTableViewCell
53 | cell.accessoryType = accessoryTypeForCellAtIndexPath(indexPath)
54 | cell.actions = actionsForCell(cell, indexPath: indexPath)
55 | return cell
56 | } else {
57 | var cell = tableView.dequeueReusableCell(withIdentifier: kCellID) as? SwipeableTableViewCell
58 | if cell == nil {
59 | cell = SwipeableTableViewCell(style: .default, reuseIdentifier: kCellID)
60 | }
61 | cell!.delegate = self
62 | if indexPath.row % 7 == 1 {
63 | let customAccessory = UILabel(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
64 | customAccessory.textAlignment = .center
65 | customAccessory.text = "❤️"
66 | customAccessory.backgroundColor = .clear
67 | cell!.accessoryView = customAccessory
68 | } else {
69 | cell!.accessoryView = nil
70 | cell!.accessoryType = accessoryTypeForCellAtIndexPath(indexPath)
71 | }
72 | cell!.actions = actionsForCell(cell!, indexPath: indexPath)
73 | if indexPath.row % 7 == 6 {
74 | cell!.textLabel?.text = "Cell \(indexPath.row) - No Swipe Action"
75 | } else {
76 | cell!.textLabel?.text = "Cell \(indexPath.row)"
77 | }
78 |
79 | cell!.textLabel?.font = .systemFont(ofSize: 18)
80 | return cell!
81 | }
82 | }
83 |
84 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
85 | let message = indexPath.row % 7 == 5 ? "Did select custom cell" : "Did select cell \(indexPath.row)"
86 | showAlert(message) {
87 |
88 | }
89 | }
90 |
91 | fileprivate func accessoryTypeForCellAtIndexPath(_ indexPath: IndexPath) -> UITableViewCell.AccessoryType {
92 | switch indexPath.row % 7 {
93 | case 0:
94 | return .none
95 | case 1:
96 | return .none
97 | case 2, 5:
98 | return .disclosureIndicator
99 | case 3:
100 | return .detailDisclosureButton
101 | case 4:
102 | return .checkmark
103 | default:
104 | return .none
105 | }
106 | }
107 |
108 | fileprivate func actionsForCell(_ cell: SwipeableTableViewCell, indexPath: IndexPath) -> [SwipeableCellAction]? {
109 | switch indexPath.row % 7 {
110 | case 0, 5:
111 | let delete = NSAttributedString(string: "删除", attributes: [.foregroundColor: UIColor.white])
112 | var deleteAction = SwipeableCellAction(title: delete, image: nil, backgroundColor: .red) {
113 | let message = indexPath.row % 7 == 5 ? "Did click “\(delete.string)” on custom cell" : "Did click “\(delete.string)” on cell \(indexPath.row)"
114 | self.showAlert(message, dismissHandler: {
115 | cell.hideActions(animated: true)
116 | })
117 | }
118 | let more = NSAttributedString(string: "更多", attributes: [.foregroundColor: UIColor.white])
119 | var moreAction = SwipeableCellAction(title: more, image: nil, backgroundColor: .lightGray) {
120 | let message = indexPath.row % 7 == 5 ? "Did click “\(more.string)” on custom cell" : "Did click “\(more.string)” on cell \(indexPath.row)"
121 | self.showAlert(message, dismissHandler: {
122 | cell.hideActions(animated: true)
123 | })
124 | }
125 | moreAction.width = 100
126 | deleteAction.width = 100
127 | return [deleteAction, moreAction]
128 |
129 | case 1:
130 | var deleteAction = SwipeableCellAction(title: NSAttributedString(string: "Delete"), image: nil, backgroundColor: .red) {
131 | let message = "Did click “Delete” at cell \(indexPath.row)"
132 | self.showAlert(message, dismissHandler: {
133 | cell.hideActions(animated: true)
134 | })
135 | }
136 | var moreAction = SwipeableCellAction(title: NSAttributedString(string: "More"), image: nil, backgroundColor: .lightGray) {
137 | let message = "Did click “More” at cell \(indexPath.row)"
138 | self.showAlert(message, dismissHandler: {
139 | cell.hideActions(animated: true)
140 | })
141 | }
142 | moreAction.width = 100
143 | deleteAction.width = 100
144 | return [deleteAction, moreAction]
145 |
146 | case 2:
147 | let delete = NSAttributedString(string: "删除", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15)])
148 | var deleteAction = SwipeableCellAction(title: delete, image: UIImage(named: "delete-icon"), backgroundColor: UIColor(red: 255 / 255, green: 90 / 255, blue: 29 / 255, alpha: 1)) {
149 | let message = "Did click “\(delete.string)” at cell \(indexPath.row)"
150 | self.showAlert(message, dismissHandler: {
151 | cell.hideActions(animated: true)
152 | })
153 | }
154 | let later = NSAttributedString(string: "稍后处理", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 15)])
155 | var laterAction = SwipeableCellAction(title: later, image: UIImage(named: "later-icon"), backgroundColor: UIColor(red: 3 / 255, green: 169 / 255, blue: 244 / 255, alpha: 1)) {
156 | let message = "Did click “\(later.string)” at cell \(indexPath.row)"
157 | self.showAlert(message, dismissHandler: {
158 | cell.hideActions(animated: true)
159 | })
160 | }
161 | deleteAction.width = 100
162 | deleteAction.verticalSpace = 6
163 | laterAction.width = 100
164 | laterAction.verticalSpace = 6
165 | return [deleteAction, laterAction]
166 |
167 | case 3:
168 | let crossAction = SwipeableCellAction(title: nil, image: UIImage(named: "cross-icon"), backgroundColor: UIColor(red: 18 / 255, green: 191 / 255, blue: 41 / 255, alpha: 1)) {
169 | let message = "Did click “Cross” at cell \(indexPath.row)"
170 | self.showAlert(message, dismissHandler: {
171 | cell.hideActions(animated: true)
172 | })
173 | }
174 | let clockAction = SwipeableCellAction(title: nil, image: UIImage(named: "clock-icon"), backgroundColor: UIColor(red: 255 / 255, green: 255 / 255, blue: 89 / 255, alpha: 1)) {
175 | let message = "Did click “Clock” at cell \(indexPath.row)"
176 | self.showAlert(message, dismissHandler: {
177 | cell.hideActions(animated: true)
178 | })
179 | }
180 | let checkAction = SwipeableCellAction(title: nil, image: UIImage(named: "check-icon"), backgroundColor: UIColor(red: 255 / 255, green: 59 / 255, blue: 48 / 255, alpha: 1)) {
181 | let message = "Did click “Check” at cell \(indexPath.row)"
182 | self.showAlert(message, dismissHandler: {
183 | cell.hideActions(animated: true)
184 | })
185 | }
186 | return [crossAction, clockAction, checkAction]
187 |
188 | case 4:
189 | let favorite = NSAttributedString(string: "收藏", attributes: [.foregroundColor: UIColor.white, .font: UIFont.systemFont(ofSize: 16)])
190 | var favoriteAction = SwipeableCellAction(title: favorite, image: nil, backgroundColor: UIColor(red: 3 / 255, green: 169 / 255, blue: 244 / 255, alpha: 1)) {
191 | let message = "Did click “\(favorite.string)” at cell \(indexPath.row)"
192 | self.showAlert(message, dismissHandler: {
193 | cell.hideActions(animated: true)
194 | })
195 | }
196 | favoriteAction.width = 120
197 | return [favoriteAction]
198 |
199 | default:
200 | return nil
201 | }
202 | }
203 |
204 | // MARK: - SwipeableTableViewCell delegate
205 | func swipeableCell(_ cell: SwipeableTableViewCell, isScrollingToState state: SwipeableCellState) {
206 | let cellState = state == .closed ? "closing" : "opening"
207 | let cellName = (cell.textLabel?.text)!
208 | print("“\(cellName)” is \(cellState)...")
209 | }
210 |
211 | func swipeableCellDidEndScroll(_ cell: SwipeableTableViewCell) {
212 | let cellName = (cell.textLabel?.text)!
213 | print("“\(cellName)” did end scroll!")
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D3C6AD881C1FC19400580522 /* SwipeableTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C6AD871C1FC19400580522 /* SwipeableTableViewCell.swift */; };
11 | D3C6AD8B1C1FCC0400580522 /* SwipeableCellAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C6AD8A1C1FCC0400580522 /* SwipeableCellAction.swift */; };
12 | D3C6AD8D1C1FE24900580522 /* SwipeableCellActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C6AD8C1C1FE24900580522 /* SwipeableCellActionsView.swift */; };
13 | /* End PBXBuildFile section */
14 |
15 | /* Begin PBXFileReference section */
16 | D3C6AD581C1FBE9600580522 /* SwipeableTableViewCell.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwipeableTableViewCell.framework; sourceTree = BUILT_PRODUCTS_DIR; };
17 | D3C6AD5D1C1FBE9600580522 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
18 | D3C6AD871C1FC19400580522 /* SwipeableTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwipeableTableViewCell.swift; sourceTree = ""; };
19 | D3C6AD8A1C1FCC0400580522 /* SwipeableCellAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwipeableCellAction.swift; sourceTree = ""; };
20 | D3C6AD8C1C1FE24900580522 /* SwipeableCellActionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwipeableCellActionsView.swift; sourceTree = ""; };
21 | /* End PBXFileReference section */
22 |
23 | /* Begin PBXFrameworksBuildPhase section */
24 | D3C6AD541C1FBE9600580522 /* Frameworks */ = {
25 | isa = PBXFrameworksBuildPhase;
26 | buildActionMask = 2147483647;
27 | files = (
28 | );
29 | runOnlyForDeploymentPostprocessing = 0;
30 | };
31 | /* End PBXFrameworksBuildPhase section */
32 |
33 | /* Begin PBXGroup section */
34 | D3C6AD4E1C1FBE9600580522 = {
35 | isa = PBXGroup;
36 | children = (
37 | D3C6AD5A1C1FBE9600580522 /* SwipeableTableViewCell */,
38 | D3C6AD591C1FBE9600580522 /* Products */,
39 | );
40 | sourceTree = "";
41 | };
42 | D3C6AD591C1FBE9600580522 /* Products */ = {
43 | isa = PBXGroup;
44 | children = (
45 | D3C6AD581C1FBE9600580522 /* SwipeableTableViewCell.framework */,
46 | );
47 | name = Products;
48 | sourceTree = "";
49 | };
50 | D3C6AD5A1C1FBE9600580522 /* SwipeableTableViewCell */ = {
51 | isa = PBXGroup;
52 | children = (
53 | D3C6AD8A1C1FCC0400580522 /* SwipeableCellAction.swift */,
54 | D3C6AD8C1C1FE24900580522 /* SwipeableCellActionsView.swift */,
55 | D3C6AD871C1FC19400580522 /* SwipeableTableViewCell.swift */,
56 | D3C6AD891C1FC1F900580522 /* Supporting Files */,
57 | );
58 | path = SwipeableTableViewCell;
59 | sourceTree = "";
60 | };
61 | D3C6AD891C1FC1F900580522 /* Supporting Files */ = {
62 | isa = PBXGroup;
63 | children = (
64 | D3C6AD5D1C1FBE9600580522 /* Info.plist */,
65 | );
66 | path = "Supporting Files";
67 | sourceTree = "";
68 | };
69 | /* End PBXGroup section */
70 |
71 | /* Begin PBXHeadersBuildPhase section */
72 | D3C6AD551C1FBE9600580522 /* Headers */ = {
73 | isa = PBXHeadersBuildPhase;
74 | buildActionMask = 2147483647;
75 | files = (
76 | );
77 | runOnlyForDeploymentPostprocessing = 0;
78 | };
79 | /* End PBXHeadersBuildPhase section */
80 |
81 | /* Begin PBXNativeTarget section */
82 | D3C6AD571C1FBE9600580522 /* SwipeableTableViewCell */ = {
83 | isa = PBXNativeTarget;
84 | buildConfigurationList = D3C6AD601C1FBE9600580522 /* Build configuration list for PBXNativeTarget "SwipeableTableViewCell" */;
85 | buildPhases = (
86 | D3C6AD531C1FBE9600580522 /* Sources */,
87 | D3C6AD541C1FBE9600580522 /* Frameworks */,
88 | D3C6AD551C1FBE9600580522 /* Headers */,
89 | D3C6AD561C1FBE9600580522 /* Resources */,
90 | );
91 | buildRules = (
92 | );
93 | dependencies = (
94 | );
95 | name = SwipeableTableViewCell;
96 | productName = SwipeableTableViewCell;
97 | productReference = D3C6AD581C1FBE9600580522 /* SwipeableTableViewCell.framework */;
98 | productType = "com.apple.product-type.framework";
99 | };
100 | /* End PBXNativeTarget section */
101 |
102 | /* Begin PBXProject section */
103 | D3C6AD4F1C1FBE9600580522 /* Project object */ = {
104 | isa = PBXProject;
105 | attributes = {
106 | LastUpgradeCheck = 1020;
107 | ORGANIZATIONNAME = Teambition;
108 | TargetAttributes = {
109 | D3C6AD571C1FBE9600580522 = {
110 | CreatedOnToolsVersion = 7.2;
111 | LastSwiftMigration = 1020;
112 | };
113 | };
114 | };
115 | buildConfigurationList = D3C6AD521C1FBE9600580522 /* Build configuration list for PBXProject "SwipeableTableViewCell" */;
116 | compatibilityVersion = "Xcode 3.2";
117 | developmentRegion = en;
118 | hasScannedForEncodings = 0;
119 | knownRegions = (
120 | en,
121 | Base,
122 | );
123 | mainGroup = D3C6AD4E1C1FBE9600580522;
124 | productRefGroup = D3C6AD591C1FBE9600580522 /* Products */;
125 | projectDirPath = "";
126 | projectRoot = "";
127 | targets = (
128 | D3C6AD571C1FBE9600580522 /* SwipeableTableViewCell */,
129 | );
130 | };
131 | /* End PBXProject section */
132 |
133 | /* Begin PBXResourcesBuildPhase section */
134 | D3C6AD561C1FBE9600580522 /* Resources */ = {
135 | isa = PBXResourcesBuildPhase;
136 | buildActionMask = 2147483647;
137 | files = (
138 | );
139 | runOnlyForDeploymentPostprocessing = 0;
140 | };
141 | /* End PBXResourcesBuildPhase section */
142 |
143 | /* Begin PBXSourcesBuildPhase section */
144 | D3C6AD531C1FBE9600580522 /* Sources */ = {
145 | isa = PBXSourcesBuildPhase;
146 | buildActionMask = 2147483647;
147 | files = (
148 | D3C6AD8B1C1FCC0400580522 /* SwipeableCellAction.swift in Sources */,
149 | D3C6AD8D1C1FE24900580522 /* SwipeableCellActionsView.swift in Sources */,
150 | D3C6AD881C1FC19400580522 /* SwipeableTableViewCell.swift in Sources */,
151 | );
152 | runOnlyForDeploymentPostprocessing = 0;
153 | };
154 | /* End PBXSourcesBuildPhase section */
155 |
156 | /* Begin XCBuildConfiguration section */
157 | D3C6AD5E1C1FBE9600580522 /* Debug */ = {
158 | isa = XCBuildConfiguration;
159 | buildSettings = {
160 | ALWAYS_SEARCH_USER_PATHS = NO;
161 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
162 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
163 | CLANG_CXX_LIBRARY = "libc++";
164 | CLANG_ENABLE_MODULES = YES;
165 | CLANG_ENABLE_OBJC_ARC = YES;
166 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
167 | CLANG_WARN_BOOL_CONVERSION = YES;
168 | CLANG_WARN_COMMA = YES;
169 | CLANG_WARN_CONSTANT_CONVERSION = YES;
170 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
171 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
172 | CLANG_WARN_EMPTY_BODY = YES;
173 | CLANG_WARN_ENUM_CONVERSION = YES;
174 | CLANG_WARN_INFINITE_RECURSION = YES;
175 | CLANG_WARN_INT_CONVERSION = YES;
176 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
177 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
178 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
179 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
180 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
181 | CLANG_WARN_STRICT_PROTOTYPES = YES;
182 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
183 | CLANG_WARN_UNREACHABLE_CODE = YES;
184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
185 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
186 | COPY_PHASE_STRIP = NO;
187 | CURRENT_PROJECT_VERSION = 1;
188 | DEBUG_INFORMATION_FORMAT = dwarf;
189 | ENABLE_STRICT_OBJC_MSGSEND = YES;
190 | ENABLE_TESTABILITY = YES;
191 | GCC_C_LANGUAGE_STANDARD = gnu99;
192 | GCC_DYNAMIC_NO_PIC = NO;
193 | GCC_NO_COMMON_BLOCKS = YES;
194 | GCC_OPTIMIZATION_LEVEL = 0;
195 | GCC_PREPROCESSOR_DEFINITIONS = (
196 | "DEBUG=1",
197 | "$(inherited)",
198 | );
199 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
200 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
201 | GCC_WARN_UNDECLARED_SELECTOR = YES;
202 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
203 | GCC_WARN_UNUSED_FUNCTION = YES;
204 | GCC_WARN_UNUSED_VARIABLE = YES;
205 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
206 | MTL_ENABLE_DEBUG_INFO = YES;
207 | ONLY_ACTIVE_ARCH = YES;
208 | SDKROOT = iphoneos;
209 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
210 | SWIFT_VERSION = "";
211 | TARGETED_DEVICE_FAMILY = "1,2";
212 | VERSIONING_SYSTEM = "apple-generic";
213 | VERSION_INFO_PREFIX = "";
214 | };
215 | name = Debug;
216 | };
217 | D3C6AD5F1C1FBE9600580522 /* Release */ = {
218 | isa = XCBuildConfiguration;
219 | buildSettings = {
220 | ALWAYS_SEARCH_USER_PATHS = NO;
221 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
223 | CLANG_CXX_LIBRARY = "libc++";
224 | CLANG_ENABLE_MODULES = YES;
225 | CLANG_ENABLE_OBJC_ARC = YES;
226 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
227 | CLANG_WARN_BOOL_CONVERSION = YES;
228 | CLANG_WARN_COMMA = YES;
229 | CLANG_WARN_CONSTANT_CONVERSION = YES;
230 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
231 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
232 | CLANG_WARN_EMPTY_BODY = YES;
233 | CLANG_WARN_ENUM_CONVERSION = YES;
234 | CLANG_WARN_INFINITE_RECURSION = YES;
235 | CLANG_WARN_INT_CONVERSION = YES;
236 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
237 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
238 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
240 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
241 | CLANG_WARN_STRICT_PROTOTYPES = YES;
242 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
243 | CLANG_WARN_UNREACHABLE_CODE = YES;
244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
245 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
246 | COPY_PHASE_STRIP = NO;
247 | CURRENT_PROJECT_VERSION = 1;
248 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
249 | ENABLE_NS_ASSERTIONS = NO;
250 | ENABLE_STRICT_OBJC_MSGSEND = YES;
251 | GCC_C_LANGUAGE_STANDARD = gnu99;
252 | GCC_NO_COMMON_BLOCKS = YES;
253 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
254 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
255 | GCC_WARN_UNDECLARED_SELECTOR = YES;
256 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
257 | GCC_WARN_UNUSED_FUNCTION = YES;
258 | GCC_WARN_UNUSED_VARIABLE = YES;
259 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
260 | MTL_ENABLE_DEBUG_INFO = NO;
261 | SDKROOT = iphoneos;
262 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
263 | SWIFT_VERSION = "";
264 | TARGETED_DEVICE_FAMILY = "1,2";
265 | VALIDATE_PRODUCT = YES;
266 | VERSIONING_SYSTEM = "apple-generic";
267 | VERSION_INFO_PREFIX = "";
268 | };
269 | name = Release;
270 | };
271 | D3C6AD611C1FBE9600580522 /* Debug */ = {
272 | isa = XCBuildConfiguration;
273 | buildSettings = {
274 | CLANG_ENABLE_MODULES = YES;
275 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
276 | DEFINES_MODULE = YES;
277 | DYLIB_COMPATIBILITY_VERSION = 1;
278 | DYLIB_CURRENT_VERSION = 1;
279 | DYLIB_INSTALL_NAME_BASE = "@rpath";
280 | INFOPLIST_FILE = "$(SRCROOT)/SwipeableTableViewCell/Supporting Files/Info.plist";
281 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
282 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
283 | PRODUCT_BUNDLE_IDENTIFIER = Teambition.SwipeableTableViewCell;
284 | PRODUCT_NAME = "$(TARGET_NAME)";
285 | SKIP_INSTALL = YES;
286 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
287 | SWIFT_VERSION = 5.0;
288 | };
289 | name = Debug;
290 | };
291 | D3C6AD621C1FBE9600580522 /* Release */ = {
292 | isa = XCBuildConfiguration;
293 | buildSettings = {
294 | CLANG_ENABLE_MODULES = YES;
295 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
296 | DEFINES_MODULE = YES;
297 | DYLIB_COMPATIBILITY_VERSION = 1;
298 | DYLIB_CURRENT_VERSION = 1;
299 | DYLIB_INSTALL_NAME_BASE = "@rpath";
300 | INFOPLIST_FILE = "$(SRCROOT)/SwipeableTableViewCell/Supporting Files/Info.plist";
301 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
302 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
303 | PRODUCT_BUNDLE_IDENTIFIER = Teambition.SwipeableTableViewCell;
304 | PRODUCT_NAME = "$(TARGET_NAME)";
305 | SKIP_INSTALL = YES;
306 | SWIFT_VERSION = 5.0;
307 | };
308 | name = Release;
309 | };
310 | /* End XCBuildConfiguration section */
311 |
312 | /* Begin XCConfigurationList section */
313 | D3C6AD521C1FBE9600580522 /* Build configuration list for PBXProject "SwipeableTableViewCell" */ = {
314 | isa = XCConfigurationList;
315 | buildConfigurations = (
316 | D3C6AD5E1C1FBE9600580522 /* Debug */,
317 | D3C6AD5F1C1FBE9600580522 /* Release */,
318 | );
319 | defaultConfigurationIsVisible = 0;
320 | defaultConfigurationName = Release;
321 | };
322 | D3C6AD601C1FBE9600580522 /* Build configuration list for PBXNativeTarget "SwipeableTableViewCell" */ = {
323 | isa = XCConfigurationList;
324 | buildConfigurations = (
325 | D3C6AD611C1FBE9600580522 /* Debug */,
326 | D3C6AD621C1FBE9600580522 /* Release */,
327 | );
328 | defaultConfigurationIsVisible = 0;
329 | defaultConfigurationName = Release;
330 | };
331 | /* End XCConfigurationList section */
332 | };
333 | rootObject = D3C6AD4F1C1FBE9600580522 /* Project object */;
334 | }
335 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D315960C2179AA90004E83A2 /* SwipeableTableViewCell.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D315960A2179AA90004E83A2 /* SwipeableTableViewCell.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
11 | D3C6AD701C1FBED500580522 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C6AD6F1C1FBED500580522 /* AppDelegate.swift */; };
12 | D3C6AD721C1FBED500580522 /* StylesExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3C6AD711C1FBED500580522 /* StylesExampleViewController.swift */; };
13 | D3C6AD751C1FBED500580522 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D3C6AD731C1FBED500580522 /* Main.storyboard */; };
14 | D3C6AD771C1FBED500580522 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D3C6AD761C1FBED500580522 /* Assets.xcassets */; };
15 | D3DB9C231D03F9C3009797E6 /* ExampleMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3DB9C221D03F9C3009797E6 /* ExampleMenuViewController.swift */; };
16 | D3DB9C251D03FC28009797E6 /* BackgroundViewExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3DB9C241D03FC28009797E6 /* BackgroundViewExampleViewController.swift */; };
17 | D3DB9C271D040092009797E6 /* BackgroundViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3DB9C261D040092009797E6 /* BackgroundViewCell.swift */; };
18 | D3DB9C291D0400AF009797E6 /* BackgroundViewSwipeableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3DB9C281D0400AF009797E6 /* BackgroundViewSwipeableCell.swift */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXCopyFilesBuildPhase section */
22 | D3DB9C301D040C95009797E6 /* Embed Frameworks */ = {
23 | isa = PBXCopyFilesBuildPhase;
24 | buildActionMask = 2147483647;
25 | dstPath = "";
26 | dstSubfolderSpec = 10;
27 | files = (
28 | D315960C2179AA90004E83A2 /* SwipeableTableViewCell.framework in Embed Frameworks */,
29 | );
30 | name = "Embed Frameworks";
31 | runOnlyForDeploymentPostprocessing = 0;
32 | };
33 | /* End PBXCopyFilesBuildPhase section */
34 |
35 | /* Begin PBXFileReference section */
36 | D315960A2179AA90004E83A2 /* SwipeableTableViewCell.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwipeableTableViewCell.framework; sourceTree = BUILT_PRODUCTS_DIR; };
37 | D3C6AD6C1C1FBED500580522 /* SwipeableTableViewCellExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwipeableTableViewCellExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
38 | D3C6AD6F1C1FBED500580522 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
39 | D3C6AD711C1FBED500580522 /* StylesExampleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StylesExampleViewController.swift; sourceTree = ""; };
40 | D3C6AD741C1FBED500580522 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
41 | D3C6AD761C1FBED500580522 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
42 | D3C6AD7B1C1FBED500580522 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | D3DB9C221D03F9C3009797E6 /* ExampleMenuViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExampleMenuViewController.swift; sourceTree = ""; };
44 | D3DB9C241D03FC28009797E6 /* BackgroundViewExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundViewExampleViewController.swift; sourceTree = ""; };
45 | D3DB9C261D040092009797E6 /* BackgroundViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundViewCell.swift; sourceTree = ""; };
46 | D3DB9C281D0400AF009797E6 /* BackgroundViewSwipeableCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundViewSwipeableCell.swift; sourceTree = ""; };
47 | /* End PBXFileReference section */
48 |
49 | /* Begin PBXFrameworksBuildPhase section */
50 | D3C6AD691C1FBED500580522 /* Frameworks */ = {
51 | isa = PBXFrameworksBuildPhase;
52 | buildActionMask = 2147483647;
53 | files = (
54 | );
55 | runOnlyForDeploymentPostprocessing = 0;
56 | };
57 | /* End PBXFrameworksBuildPhase section */
58 |
59 | /* Begin PBXGroup section */
60 | D3C6AD631C1FBED500580522 = {
61 | isa = PBXGroup;
62 | children = (
63 | D315960A2179AA90004E83A2 /* SwipeableTableViewCell.framework */,
64 | D3C6AD6E1C1FBED500580522 /* SwipeableTableViewCellExample */,
65 | D3C6AD6D1C1FBED500580522 /* Products */,
66 | );
67 | sourceTree = "";
68 | };
69 | D3C6AD6D1C1FBED500580522 /* Products */ = {
70 | isa = PBXGroup;
71 | children = (
72 | D3C6AD6C1C1FBED500580522 /* SwipeableTableViewCellExample.app */,
73 | );
74 | name = Products;
75 | sourceTree = "";
76 | };
77 | D3C6AD6E1C1FBED500580522 /* SwipeableTableViewCellExample */ = {
78 | isa = PBXGroup;
79 | children = (
80 | D3C6AD6F1C1FBED500580522 /* AppDelegate.swift */,
81 | D3DB9C221D03F9C3009797E6 /* ExampleMenuViewController.swift */,
82 | D3C6AD711C1FBED500580522 /* StylesExampleViewController.swift */,
83 | D3DB9C241D03FC28009797E6 /* BackgroundViewExampleViewController.swift */,
84 | D3DB9C281D0400AF009797E6 /* BackgroundViewSwipeableCell.swift */,
85 | D3DB9C261D040092009797E6 /* BackgroundViewCell.swift */,
86 | D3C6AD731C1FBED500580522 /* Main.storyboard */,
87 | D3C6AD761C1FBED500580522 /* Assets.xcassets */,
88 | D3C6AD7B1C1FBED500580522 /* Info.plist */,
89 | );
90 | path = SwipeableTableViewCellExample;
91 | sourceTree = "";
92 | };
93 | /* End PBXGroup section */
94 |
95 | /* Begin PBXNativeTarget section */
96 | D3C6AD6B1C1FBED500580522 /* SwipeableTableViewCellExample */ = {
97 | isa = PBXNativeTarget;
98 | buildConfigurationList = D3C6AD7E1C1FBED500580522 /* Build configuration list for PBXNativeTarget "SwipeableTableViewCellExample" */;
99 | buildPhases = (
100 | D3C6AD681C1FBED500580522 /* Sources */,
101 | D3C6AD691C1FBED500580522 /* Frameworks */,
102 | D3C6AD6A1C1FBED500580522 /* Resources */,
103 | D3DB9C301D040C95009797E6 /* Embed Frameworks */,
104 | );
105 | buildRules = (
106 | );
107 | dependencies = (
108 | );
109 | name = SwipeableTableViewCellExample;
110 | productName = SwipeableTableViewCellExample;
111 | productReference = D3C6AD6C1C1FBED500580522 /* SwipeableTableViewCellExample.app */;
112 | productType = "com.apple.product-type.application";
113 | };
114 | /* End PBXNativeTarget section */
115 |
116 | /* Begin PBXProject section */
117 | D3C6AD641C1FBED500580522 /* Project object */ = {
118 | isa = PBXProject;
119 | attributes = {
120 | LastSwiftUpdateCheck = 0720;
121 | LastUpgradeCheck = 1020;
122 | ORGANIZATIONNAME = Teambition;
123 | TargetAttributes = {
124 | D3C6AD6B1C1FBED500580522 = {
125 | CreatedOnToolsVersion = 7.2;
126 | LastSwiftMigration = 0900;
127 | ProvisioningStyle = Manual;
128 | };
129 | };
130 | };
131 | buildConfigurationList = D3C6AD671C1FBED500580522 /* Build configuration list for PBXProject "SwipeableTableViewCellExample" */;
132 | compatibilityVersion = "Xcode 3.2";
133 | developmentRegion = en;
134 | hasScannedForEncodings = 0;
135 | knownRegions = (
136 | en,
137 | Base,
138 | );
139 | mainGroup = D3C6AD631C1FBED500580522;
140 | productRefGroup = D3C6AD6D1C1FBED500580522 /* Products */;
141 | projectDirPath = "";
142 | projectRoot = "";
143 | targets = (
144 | D3C6AD6B1C1FBED500580522 /* SwipeableTableViewCellExample */,
145 | );
146 | };
147 | /* End PBXProject section */
148 |
149 | /* Begin PBXResourcesBuildPhase section */
150 | D3C6AD6A1C1FBED500580522 /* Resources */ = {
151 | isa = PBXResourcesBuildPhase;
152 | buildActionMask = 2147483647;
153 | files = (
154 | D3C6AD771C1FBED500580522 /* Assets.xcassets in Resources */,
155 | D3C6AD751C1FBED500580522 /* Main.storyboard in Resources */,
156 | );
157 | runOnlyForDeploymentPostprocessing = 0;
158 | };
159 | /* End PBXResourcesBuildPhase section */
160 |
161 | /* Begin PBXSourcesBuildPhase section */
162 | D3C6AD681C1FBED500580522 /* Sources */ = {
163 | isa = PBXSourcesBuildPhase;
164 | buildActionMask = 2147483647;
165 | files = (
166 | D3C6AD721C1FBED500580522 /* StylesExampleViewController.swift in Sources */,
167 | D3DB9C251D03FC28009797E6 /* BackgroundViewExampleViewController.swift in Sources */,
168 | D3C6AD701C1FBED500580522 /* AppDelegate.swift in Sources */,
169 | D3DB9C231D03F9C3009797E6 /* ExampleMenuViewController.swift in Sources */,
170 | D3DB9C291D0400AF009797E6 /* BackgroundViewSwipeableCell.swift in Sources */,
171 | D3DB9C271D040092009797E6 /* BackgroundViewCell.swift in Sources */,
172 | );
173 | runOnlyForDeploymentPostprocessing = 0;
174 | };
175 | /* End PBXSourcesBuildPhase section */
176 |
177 | /* Begin PBXVariantGroup section */
178 | D3C6AD731C1FBED500580522 /* Main.storyboard */ = {
179 | isa = PBXVariantGroup;
180 | children = (
181 | D3C6AD741C1FBED500580522 /* Base */,
182 | );
183 | name = Main.storyboard;
184 | sourceTree = "";
185 | };
186 | /* End PBXVariantGroup section */
187 |
188 | /* Begin XCBuildConfiguration section */
189 | D3C6AD7C1C1FBED500580522 /* Debug */ = {
190 | isa = XCBuildConfiguration;
191 | buildSettings = {
192 | ALWAYS_SEARCH_USER_PATHS = NO;
193 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
194 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
195 | CLANG_CXX_LIBRARY = "libc++";
196 | CLANG_ENABLE_MODULES = YES;
197 | CLANG_ENABLE_OBJC_ARC = YES;
198 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
199 | CLANG_WARN_BOOL_CONVERSION = YES;
200 | CLANG_WARN_COMMA = YES;
201 | CLANG_WARN_CONSTANT_CONVERSION = YES;
202 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
203 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
204 | CLANG_WARN_EMPTY_BODY = YES;
205 | CLANG_WARN_ENUM_CONVERSION = YES;
206 | CLANG_WARN_INFINITE_RECURSION = YES;
207 | CLANG_WARN_INT_CONVERSION = YES;
208 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
209 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
210 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
211 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
212 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
213 | CLANG_WARN_STRICT_PROTOTYPES = YES;
214 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
215 | CLANG_WARN_UNREACHABLE_CODE = YES;
216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
217 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
218 | COPY_PHASE_STRIP = NO;
219 | DEBUG_INFORMATION_FORMAT = dwarf;
220 | ENABLE_STRICT_OBJC_MSGSEND = YES;
221 | ENABLE_TESTABILITY = YES;
222 | GCC_C_LANGUAGE_STANDARD = gnu99;
223 | GCC_DYNAMIC_NO_PIC = NO;
224 | GCC_NO_COMMON_BLOCKS = YES;
225 | GCC_OPTIMIZATION_LEVEL = 0;
226 | GCC_PREPROCESSOR_DEFINITIONS = (
227 | "DEBUG=1",
228 | "$(inherited)",
229 | );
230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
232 | GCC_WARN_UNDECLARED_SELECTOR = YES;
233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
234 | GCC_WARN_UNUSED_FUNCTION = YES;
235 | GCC_WARN_UNUSED_VARIABLE = YES;
236 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
237 | MTL_ENABLE_DEBUG_INFO = YES;
238 | ONLY_ACTIVE_ARCH = YES;
239 | SDKROOT = iphoneos;
240 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
241 | SWIFT_VERSION = "";
242 | TARGETED_DEVICE_FAMILY = "1,2";
243 | };
244 | name = Debug;
245 | };
246 | D3C6AD7D1C1FBED500580522 /* Release */ = {
247 | isa = XCBuildConfiguration;
248 | buildSettings = {
249 | ALWAYS_SEARCH_USER_PATHS = NO;
250 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
252 | CLANG_CXX_LIBRARY = "libc++";
253 | CLANG_ENABLE_MODULES = YES;
254 | CLANG_ENABLE_OBJC_ARC = YES;
255 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
256 | CLANG_WARN_BOOL_CONVERSION = YES;
257 | CLANG_WARN_COMMA = YES;
258 | CLANG_WARN_CONSTANT_CONVERSION = YES;
259 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
260 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
261 | CLANG_WARN_EMPTY_BODY = YES;
262 | CLANG_WARN_ENUM_CONVERSION = YES;
263 | CLANG_WARN_INFINITE_RECURSION = YES;
264 | CLANG_WARN_INT_CONVERSION = YES;
265 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
266 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
267 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
269 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
270 | CLANG_WARN_STRICT_PROTOTYPES = YES;
271 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
272 | CLANG_WARN_UNREACHABLE_CODE = YES;
273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
274 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
275 | COPY_PHASE_STRIP = NO;
276 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
277 | ENABLE_NS_ASSERTIONS = NO;
278 | ENABLE_STRICT_OBJC_MSGSEND = YES;
279 | GCC_C_LANGUAGE_STANDARD = gnu99;
280 | GCC_NO_COMMON_BLOCKS = YES;
281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
283 | GCC_WARN_UNDECLARED_SELECTOR = YES;
284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
285 | GCC_WARN_UNUSED_FUNCTION = YES;
286 | GCC_WARN_UNUSED_VARIABLE = YES;
287 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
288 | MTL_ENABLE_DEBUG_INFO = NO;
289 | SDKROOT = iphoneos;
290 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
291 | SWIFT_VERSION = "";
292 | TARGETED_DEVICE_FAMILY = "1,2";
293 | VALIDATE_PRODUCT = YES;
294 | };
295 | name = Release;
296 | };
297 | D3C6AD7F1C1FBED500580522 /* Debug */ = {
298 | isa = XCBuildConfiguration;
299 | buildSettings = {
300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
301 | CODE_SIGN_STYLE = Manual;
302 | DEVELOPMENT_TEAM = "";
303 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
304 | INFOPLIST_FILE = SwipeableTableViewCellExample/Info.plist;
305 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
306 | PRODUCT_BUNDLE_IDENTIFIER = Teambition.SwipeableTableViewCellExample;
307 | PRODUCT_NAME = "$(TARGET_NAME)";
308 | PROVISIONING_PROFILE_SPECIFIER = "";
309 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
310 | SWIFT_VERSION = 5.0;
311 | };
312 | name = Debug;
313 | };
314 | D3C6AD801C1FBED500580522 /* Release */ = {
315 | isa = XCBuildConfiguration;
316 | buildSettings = {
317 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
318 | CODE_SIGN_STYLE = Manual;
319 | DEVELOPMENT_TEAM = "";
320 | FRAMEWORK_SEARCH_PATHS = "$(inherited)";
321 | INFOPLIST_FILE = SwipeableTableViewCellExample/Info.plist;
322 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
323 | PRODUCT_BUNDLE_IDENTIFIER = Teambition.SwipeableTableViewCellExample;
324 | PRODUCT_NAME = "$(TARGET_NAME)";
325 | PROVISIONING_PROFILE_SPECIFIER = "";
326 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
327 | SWIFT_VERSION = 5.0;
328 | };
329 | name = Release;
330 | };
331 | /* End XCBuildConfiguration section */
332 |
333 | /* Begin XCConfigurationList section */
334 | D3C6AD671C1FBED500580522 /* Build configuration list for PBXProject "SwipeableTableViewCellExample" */ = {
335 | isa = XCConfigurationList;
336 | buildConfigurations = (
337 | D3C6AD7C1C1FBED500580522 /* Debug */,
338 | D3C6AD7D1C1FBED500580522 /* Release */,
339 | );
340 | defaultConfigurationIsVisible = 0;
341 | defaultConfigurationName = Release;
342 | };
343 | D3C6AD7E1C1FBED500580522 /* Build configuration list for PBXNativeTarget "SwipeableTableViewCellExample" */ = {
344 | isa = XCConfigurationList;
345 | buildConfigurations = (
346 | D3C6AD7F1C1FBED500580522 /* Debug */,
347 | D3C6AD801C1FBED500580522 /* Release */,
348 | );
349 | defaultConfigurationIsVisible = 0;
350 | defaultConfigurationName = Release;
351 | };
352 | /* End XCConfigurationList section */
353 | };
354 | rootObject = D3C6AD641C1FBED500580522 /* Project object */;
355 | }
356 |
--------------------------------------------------------------------------------
/SwipeableTableViewCellExample/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 |
50 |
51 |
57 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
116 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
161 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
--------------------------------------------------------------------------------
/SwipeableTableViewCell/SwipeableTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwipeableTableViewCell.swift
3 | // SwipeableTableViewCell
4 | //
5 | // Created by 洪鑫 on 15/12/15.
6 | // Copyright © 2015年 Teambition. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | let kAccessoryTrailingSpace: CGFloat = 15
12 | let kSectionIndexWidth: CGFloat = 15
13 | let kTableViewPanState = "state"
14 |
15 | public enum SwipeableCellState {
16 | case closed
17 | case swiped
18 | }
19 |
20 | public protocol SwipeableTableViewCellDelegate: class {
21 | func swipeableCell(_ cell: SwipeableTableViewCell, isScrollingToState state: SwipeableCellState)
22 | func swipeableCellSwipeEnabled(_ cell: SwipeableTableViewCell) -> Bool
23 | func allowMultipleCellsSwipedSimultaneously() -> Bool
24 | func swipeableCellDidEndScroll(_ cell: SwipeableTableViewCell)
25 | }
26 |
27 | public extension SwipeableTableViewCellDelegate {
28 | func swipeableCell(_ cell: SwipeableTableViewCell, isScrollingToState state: SwipeableCellState) {
29 |
30 | }
31 |
32 | func swipeableCellSwipeEnabled(_ cell: SwipeableTableViewCell) -> Bool {
33 | return true
34 | }
35 |
36 | func allowMultipleCellsSwipedSimultaneously() -> Bool {
37 | return false
38 | }
39 |
40 | func swipeableCellDidEndScroll(_ cell: SwipeableTableViewCell) {
41 |
42 | }
43 | }
44 |
45 | open class SwipeableTableViewCell: UITableViewCell, UIScrollViewDelegate {
46 | open weak var delegate: SwipeableTableViewCellDelegate?
47 | open fileprivate(set) var state: SwipeableCellState = .closed {
48 | didSet {
49 | if state != oldValue {
50 | updateContainerViewBackgroundColor()
51 | }
52 | }
53 | }
54 | open var actions: [SwipeableCellAction]? {
55 | didSet {
56 | actionsView.setActions(actions)
57 | actionsView.layoutIfNeeded()
58 | layoutIfNeeded()
59 | }
60 | }
61 |
62 | fileprivate weak var tableView: UITableView? {
63 | didSet {
64 | removeOldTableViewPanObserver()
65 | tableViewPanGestureRecognizer = nil
66 | if let tableView = tableView {
67 | tableViewPanGestureRecognizer = tableView.panGestureRecognizer
68 | if let dataSource = tableView.dataSource {
69 | if dataSource.responds(to: #selector(UITableViewDataSource.sectionIndexTitles(for:))) {
70 | if let _ = dataSource.sectionIndexTitles?(for: tableView) {
71 | additionalPadding = kSectionIndexWidth
72 | }
73 | }
74 | }
75 | tableView.isDirectionalLockEnabled = true
76 | tapGesture.require(toFail: tableView.panGestureRecognizer)
77 | tableViewPanGestureRecognizer!.addObserver(self, forKeyPath: kTableViewPanState, options: [.new], context: nil)
78 | }
79 | }
80 | }
81 | fileprivate var tableViewPanGestureRecognizer: UIPanGestureRecognizer?
82 | fileprivate var additionalPadding: CGFloat = 0 {
83 | didSet {
84 | trainingOffset.constant = -additionalPadding
85 | layoutIfNeeded()
86 | }
87 | }
88 | open fileprivate(set) var containerView: UIView!
89 | open fileprivate(set) lazy var scrollView: SwipeableCellScrollView = {
90 | let scrollView = SwipeableCellScrollView()
91 | scrollView.translatesAutoresizingMaskIntoConstraints = false
92 | scrollView.showsHorizontalScrollIndicator = false
93 | scrollView.scrollsToTop = false
94 | scrollView.isScrollEnabled = true
95 | return scrollView
96 | }()
97 | lazy var tapGesture: UITapGestureRecognizer = { [unowned self] in
98 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SwipeableTableViewCell.scrollViewTapped(_:)))
99 | tapGesture.cancelsTouchesInView = false
100 | tapGesture.numberOfTapsRequired = 1
101 | return tapGesture
102 | }()
103 | lazy var longPressGesture: UILongPressGestureRecognizer = {
104 | let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(SwipeableTableViewCell.scrollViewLongPressed(_:)))
105 | longPressGesture.cancelsTouchesInView = false
106 | longPressGesture.minimumPressDuration = 0.16
107 | return longPressGesture
108 | }()
109 |
110 | lazy var actionsView: SwipeableCellActionsView = { [unowned self] in
111 | let actions = self.actions ?? []
112 | let actionsView = SwipeableCellActionsView(actions: actions, parentCell: self)
113 | return actionsView
114 | }()
115 | lazy var clipView: UIView = { [unowned self] in
116 | let view = UIView(frame: self.frame)
117 | view.translatesAutoresizingMaskIntoConstraints = false
118 | view.clipsToBounds = false
119 | return view
120 | }()
121 | fileprivate var clipViewConstraint = NSLayoutConstraint()
122 | fileprivate var trainingOffset = NSLayoutConstraint()
123 | fileprivate var isLayoutUpdating = false
124 |
125 | // MARK: - Life cycle
126 | public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
127 | super.init(style: style, reuseIdentifier: reuseIdentifier)
128 | configureSwipeableCell()
129 | }
130 |
131 | required public init?(coder aDecoder: NSCoder) {
132 | super.init(coder: aDecoder)
133 | configureSwipeableCell()
134 | }
135 |
136 | override open func layoutSubviews() {
137 | super.layoutSubviews()
138 | updateContainerViewBackgroundColor()
139 |
140 | containerView.frame = contentView.frame
141 | containerView.frame.size.width = frame.width - additionalPadding
142 | containerView.frame.size.height = frame.height
143 | scrollView.contentSize = CGSize(width: frame.width + actionsView.frame.width, height: frame.height)
144 | if !scrollView.isTracking && !scrollView.isDecelerating {
145 | scrollView.contentOffset = contentOffset(of: state)
146 | }
147 | updateCell()
148 | }
149 |
150 | override open func prepareForReuse() {
151 | super.prepareForReuse()
152 | if state != .closed {
153 | hideActions(animated: false)
154 | }
155 | }
156 |
157 | deinit {
158 | scrollView.delegate = nil
159 | removeOldTableViewPanObserver()
160 | }
161 |
162 | // MARK: - Overriding
163 | override open func didMoveToSuperview() {
164 | tableView = nil
165 | if let tableView = superview as? UITableView {
166 | self.tableView = tableView
167 | } else if let tableView = superview?.superview as? UITableView {
168 | self.tableView = tableView
169 | }
170 | }
171 |
172 | override open var frame: CGRect {
173 | willSet {
174 | isLayoutUpdating = true
175 | }
176 | didSet {
177 | isLayoutUpdating = false
178 | let widthChanged = frame.width != oldValue.width
179 | if widthChanged {
180 | layoutIfNeeded()
181 | }
182 | }
183 | }
184 |
185 | override open func setSelected(_ selected: Bool, animated: Bool) {
186 | actionsView.pushBackgroundColors()
187 | super.setSelected(selected, animated: animated)
188 | actionsView.popBackgroundColors()
189 | }
190 |
191 | // MARK: - TableView related
192 | fileprivate func removeOldTableViewPanObserver() {
193 | tableViewPanGestureRecognizer?.removeObserver(self, forKeyPath: kTableViewPanState)
194 | }
195 |
196 | override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
197 | if let keyPath = keyPath, let object = object as? UIPanGestureRecognizer, let tableViewPanGestureRecognizer = tableViewPanGestureRecognizer {
198 | if keyPath == kTableViewPanState && object == tableViewPanGestureRecognizer {
199 | if let change = change, let new = change[.newKey] as? Int, (new == 2 || new == 3) {
200 | setHighlighted(false, animated: false)
201 | }
202 | }
203 | }
204 | }
205 |
206 | fileprivate func shouldHighlight() -> Bool {
207 | if let tableView = tableView, let delegate = tableView.delegate {
208 | if delegate.responds(to: #selector(UITableViewDelegate.tableView(_:shouldHighlightRowAt:))) {
209 | if let cellIndexPath = tableView.indexPathForRow(at: center) {
210 | return delegate.tableView!(tableView, shouldHighlightRowAt: cellIndexPath)
211 | }
212 | }
213 | }
214 | return true
215 | }
216 |
217 | fileprivate func selectCell() {
218 | if state == .swiped {
219 | return
220 | }
221 |
222 | if let tableView = tableView, let delegate = tableView.delegate {
223 | var cellIndexPath = tableView.indexPathForRow(at: center)
224 | if delegate.responds(to: #selector(UITableViewDelegate.tableView(_:willSelectRowAt:))) {
225 | if let indexPath = cellIndexPath {
226 | cellIndexPath = delegate.tableView!(tableView, willSelectRowAt: indexPath)
227 | }
228 | }
229 | if let indexPath = cellIndexPath {
230 | tableView.selectRow(at: indexPath, animated: false, scrollPosition: .none)
231 | if delegate.responds(to: #selector(UITableViewDelegate.tableView(_:didSelectRowAt:))) {
232 | delegate.tableView!(tableView, didSelectRowAt: indexPath)
233 | }
234 | }
235 | }
236 | }
237 |
238 | fileprivate func deselectCell() {
239 | if state == .swiped {
240 | return
241 | }
242 |
243 | if let tableView = tableView, let delegate = tableView.delegate {
244 | var cellIndexPath = tableView.indexPathForRow(at: center)
245 | if delegate.responds(to: #selector(UITableViewDelegate.tableView(_:willDeselectRowAt:))) {
246 | if let indexPath = cellIndexPath {
247 | cellIndexPath = delegate.tableView!(tableView, willDeselectRowAt: indexPath)
248 | }
249 | }
250 | if let indexPath = cellIndexPath {
251 | tableView.deselectRow(at: indexPath, animated: false)
252 | if delegate.responds(to: #selector(UITableViewDelegate.tableView(_:didDeselectRowAt:))) {
253 | delegate.tableView!(tableView, didDeselectRowAt: indexPath)
254 | }
255 | }
256 | }
257 | }
258 |
259 | // MARK: - Helper
260 | open func showActions(animated: Bool) {
261 | DispatchQueue.main.async {
262 | self.scrollView.setContentOffset(self.contentOffset(of: .swiped), animated: animated)
263 | self.delegate?.swipeableCell(self, isScrollingToState: .swiped)
264 | }
265 | }
266 |
267 | open func hideActions(animated: Bool) {
268 | DispatchQueue.main.async {
269 | self.scrollView.setContentOffset(self.contentOffset(of: .closed), animated: animated)
270 | self.delegate?.swipeableCell(self, isScrollingToState: .closed)
271 | }
272 | }
273 |
274 | open func hideAllOtherCellsActions(animated: Bool) {
275 | if let tableView = tableView {
276 | for cell in tableView.visibleCells {
277 | if let cell = cell as? SwipeableTableViewCell {
278 | if cell != self {
279 | cell.hideActions(animated: animated)
280 | }
281 | }
282 | }
283 | }
284 | }
285 |
286 | fileprivate func contentOffset(of state: SwipeableCellState) -> CGPoint {
287 | return state == .swiped ? CGPoint(x: actionsView.frame.width, y: 0) : .zero
288 | }
289 |
290 | fileprivate func updateCell() {
291 | if isLayoutUpdating {
292 | return
293 | }
294 |
295 | if scrollView.contentOffset.equalTo(contentOffset(of: .closed)) {
296 | state = .closed
297 | } else {
298 | state = .swiped
299 | }
300 |
301 | if let frame = contentView.superview?.convert(contentView.frame, to: self) {
302 | var frame = frame
303 | frame.size.width = self.frame.width
304 | clipViewConstraint.constant = min(0, frame.maxX - self.frame.maxX)
305 |
306 | actionsView.isHidden = clipViewConstraint.constant == 0
307 |
308 | if let accessoryView = accessoryView {
309 | if !isEditing {
310 | accessoryView.frame.origin.x = frame.width - accessoryView.frame.width - kAccessoryTrailingSpace + frame.minX - additionalPadding
311 | }
312 | } else if accessoryType != .none && !isEditing {
313 | if let subviews = scrollView.superview?.subviews {
314 | for subview in subviews {
315 | if let accessory = subview as? UIButton {
316 | accessory.frame.origin.x = frame.width - accessory.frame.width - kAccessoryTrailingSpace + frame.minX - additionalPadding
317 | } else if String(describing: type(of: subview)) == "UITableViewCellDetailDisclosureView" {
318 | subview.frame.origin.x = frame.width - subview.frame.width - kAccessoryTrailingSpace + frame.minX - additionalPadding
319 | }
320 | }
321 | }
322 | }
323 |
324 | if !scrollView.isDragging && !scrollView.isDecelerating {
325 | tapGesture.isEnabled = true
326 | longPressGesture.isEnabled = state == .closed
327 | } else {
328 | tapGesture.isEnabled = false
329 | longPressGesture.isEnabled = false
330 | }
331 |
332 | scrollView.isScrollEnabled = !isEditing
333 | }
334 |
335 | }
336 |
337 | fileprivate func configureSwipeableCell() {
338 | state = .closed
339 | isLayoutUpdating = false
340 | scrollView.delegate = self
341 | containerView = UIView()
342 | scrollView.addSubview(containerView)
343 | insertSubview(scrollView, at: 0)
344 | containerView.addSubview(contentView)
345 |
346 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollView]))
347 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[scrollView]|", options: [], metrics: nil, views: ["scrollView": scrollView]))
348 |
349 | tapGesture.delegate = self
350 | scrollView.addGestureRecognizer(tapGesture)
351 | longPressGesture.delegate = self
352 | scrollView.addGestureRecognizer(longPressGesture)
353 |
354 | scrollView.insertSubview(clipView, at: 0)
355 | clipViewConstraint = NSLayoutConstraint(item: clipView, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0)
356 | clipViewConstraint.priority = .defaultHigh
357 | trainingOffset = NSLayoutConstraint(item: clipView, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0)
358 | addConstraint(NSLayoutConstraint(item: clipView, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1, constant: 0))
359 | addConstraint(NSLayoutConstraint(item: clipView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0))
360 | addConstraint(trainingOffset)
361 | addConstraint(clipViewConstraint)
362 |
363 | clipView.addSubview(actionsView)
364 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[actionsView]|", options: [], metrics: nil, views: ["actionsView": actionsView]))
365 | addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[actionsView]|", options: [], metrics: nil, views: ["actionsView": actionsView]))
366 | }
367 |
368 | fileprivate func updateContainerViewBackgroundColor() {
369 | if isSelected || isHighlighted || state == .closed {
370 | containerView.backgroundColor = .clear
371 | } else {
372 | if backgroundColor == .clear || backgroundColor == nil {
373 | containerView.backgroundColor = .white
374 | } else {
375 | containerView.backgroundColor = backgroundColor
376 | }
377 | }
378 | }
379 |
380 | fileprivate func shouldAllowMultipleCellsSwipedSimultaneously() -> Bool {
381 | return delegate?.allowMultipleCellsSwipedSimultaneously() ?? false
382 | }
383 |
384 | fileprivate func swipeEnabled() -> Bool {
385 | return delegate?.swipeableCellSwipeEnabled(self) ?? true
386 | }
387 |
388 | // MARK: - Selector
389 | @objc func scrollViewTapped(_ gestureRecognizer: UIGestureRecognizer) {
390 | if state == .closed {
391 | if let tableView = tableView {
392 | if tableView.hasSwipedCells() {
393 | hideAllOtherCellsActions(animated: true)
394 | return
395 | }
396 | }
397 |
398 | if isSelected {
399 | deselectCell()
400 | } else if shouldHighlight() {
401 | selectCell()
402 | }
403 | } else {
404 | hideActions(animated: true)
405 | }
406 | }
407 |
408 | @objc func scrollViewLongPressed(_ gestureRecognizer: UIGestureRecognizer) {
409 | switch gestureRecognizer.state {
410 | case .began:
411 | if shouldHighlight() && !isHighlighted {
412 | setHighlighted(true, animated: false)
413 | }
414 |
415 | case .ended:
416 | if isHighlighted {
417 | setHighlighted(false, animated: false)
418 | scrollViewTapped(gestureRecognizer)
419 | }
420 |
421 | case .cancelled, .failed:
422 | setHighlighted(false, animated: false)
423 |
424 | default:
425 | break
426 | }
427 | }
428 |
429 | // MARK: - UIScrollView delegate
430 | open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) {
431 | let currentLength = abs(clipViewConstraint.constant)
432 | let totalLength = actionsView.frame.width
433 | var targetState: SwipeableCellState = .closed
434 |
435 | if velocity.x > 0.5 {
436 | targetState = .swiped
437 | } else if velocity.x < -0.5 {
438 | targetState = .closed
439 | } else {
440 | if currentLength >= totalLength / 2 {
441 | targetState = .swiped
442 | } else {
443 | targetState = .closed
444 | }
445 | }
446 | let targetLocation = contentOffset(of: targetState)
447 | targetContentOffset.pointee = targetLocation
448 |
449 | delegate?.swipeableCell(self, isScrollingToState: targetState)
450 |
451 | if state != .closed && !shouldAllowMultipleCellsSwipedSimultaneously() {
452 | hideAllOtherCellsActions(animated: true)
453 | }
454 | }
455 |
456 | open func scrollViewDidScroll(_ scrollView: UIScrollView) {
457 | if isSelected {
458 | deselectCell()
459 | }
460 | if !swipeEnabled() {
461 | scrollView.contentOffset = contentOffset(of: .closed)
462 | }
463 | updateCell()
464 | }
465 |
466 | open func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
467 | updateCell()
468 | delegate?.swipeableCellDidEndScroll(self)
469 | }
470 |
471 | open func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
472 | updateCell()
473 | delegate?.swipeableCellDidEndScroll(self)
474 | }
475 |
476 | open func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
477 | if !decelerate {
478 | tapGesture.isEnabled = true
479 | }
480 | }
481 |
482 | // MARK: - UIGestureRecognizer delegate
483 | override open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
484 | if let panGesture = tableView?.panGestureRecognizer {
485 | if (gestureRecognizer == panGesture && otherGestureRecognizer == longPressGesture) || (gestureRecognizer == longPressGesture && otherGestureRecognizer == panGesture) {
486 | if let tableView = tableView {
487 | if tableView.hasSwipedCells() {
488 | hideAllOtherCellsActions(animated: true)
489 | }
490 | }
491 | return true
492 | }
493 | }
494 | return false
495 | }
496 |
497 | override open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
498 | if let view = touch.view {
499 | return !(view is UIControl)
500 | }
501 | return true
502 | }
503 | }
504 |
505 | public class SwipeableCellScrollView: UIScrollView {
506 | override public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
507 | if gestureRecognizer == panGestureRecognizer {
508 | let gesture = gestureRecognizer as! UIPanGestureRecognizer
509 | let translation = gesture.translation(in: gesture.view)
510 | return abs(translation.y) <= abs(translation.x)
511 | }
512 | return true
513 | }
514 |
515 | public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
516 | if gestureRecognizer is UIPanGestureRecognizer {
517 | let gesture = gestureRecognizer as! UIPanGestureRecognizer
518 | let yVelocity = gesture.velocity(in: gesture.view).y
519 | return abs(yVelocity) <= 0.25
520 | }
521 | return true
522 | }
523 | }
524 |
525 | public extension UITableView {
526 | func hideAllSwipeableCellsActions(animated: Bool) {
527 | for cell in visibleCells {
528 | if let cell = cell as? SwipeableTableViewCell {
529 | cell.hideActions(animated: animated)
530 | }
531 | }
532 | }
533 |
534 | func hasSwipedCells() -> Bool {
535 | for cell in visibleCells {
536 | if let cell = cell as? SwipeableTableViewCell {
537 | if cell.state == .swiped {
538 | return true
539 | }
540 | }
541 | }
542 | return false
543 | }
544 | }
545 |
--------------------------------------------------------------------------------