├── DMSwipeCards
├── Assets
│ └── .gitkeep
└── Classes
│ ├── .gitkeep
│ ├── DMSwipeCardsView.swift
│ └── DMSwipeCard.swift
├── _Pods.xcodeproj
├── Screenshots
├── 01.png
├── 02.png
└── 03.png
├── screenshot_1482145004.png
├── Example
├── Podfile
├── DMSwipeCards.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ └── DMSwipeCards-Example.xcscheme
│ └── project.pbxproj
├── DMSwipeCards.xcworkspace
│ └── contents.xcworkspacedata
├── DMSwipeCards
│ ├── AppDelegate.swift
│ ├── Images.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.xib
│ └── ViewController.swift
└── Tests
│ ├── Info.plist
│ └── Tests.swift
├── DMSwipeCards.podspec
├── LICENSE
├── .gitignore
└── README.md
/DMSwipeCards/Assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/DMSwipeCards/Classes/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/_Pods.xcodeproj:
--------------------------------------------------------------------------------
1 | Example/Pods/Pods.xcodeproj
--------------------------------------------------------------------------------
/Screenshots/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D-32/DMSwipeCards/HEAD/Screenshots/01.png
--------------------------------------------------------------------------------
/Screenshots/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D-32/DMSwipeCards/HEAD/Screenshots/02.png
--------------------------------------------------------------------------------
/Screenshots/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D-32/DMSwipeCards/HEAD/Screenshots/03.png
--------------------------------------------------------------------------------
/screenshot_1482145004.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/D-32/DMSwipeCards/HEAD/screenshot_1482145004.png
--------------------------------------------------------------------------------
/Example/Podfile:
--------------------------------------------------------------------------------
1 | use_frameworks!
2 |
3 | target 'DMSwipeCards_Example' do
4 | pod 'DMSwipeCards', :path => '../'
5 |
6 | target 'DMSwipeCards_Tests' do
7 | inherit! :search_paths
8 |
9 |
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // DMSwipeCards
4 | //
5 | // Created by Dylan Marriott on 12/18/2016.
6 | // Copyright (c) 2016 Dylan Marriott. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | return true
19 | }
20 |
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Example/Tests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Example/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import XCTest
3 | import DMSwipeCards
4 |
5 | class Tests: XCTestCase {
6 |
7 | override func setUp() {
8 | super.setUp()
9 | // Put setup code here. This method is called before the invocation of each test method in the class.
10 | }
11 |
12 | override func tearDown() {
13 | // Put teardown code here. This method is called after the invocation of each test method in the class.
14 | super.tearDown()
15 | }
16 |
17 | func testExample() {
18 | // This is an example of a functional test case.
19 | XCTAssert(true, "Pass")
20 | }
21 |
22 | func testPerformanceExample() {
23 | // This is an example of a performance test case.
24 | self.measure() {
25 | // Put the code you want to measure the time of here.
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/DMSwipeCards.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'DMSwipeCards'
3 | s.version = '1.0.3'
4 | s.summary = 'Tinder like card interface'
5 |
6 | s.description = <<-DESC
7 | Written in Swift 3, supports custom views for the card and the overlay. Views get loaded lazily, so there's no issues in loading a huge amount of cards.
8 | DESC
9 |
10 | s.homepage = 'https://github.com/d-32/DMSwipeCards'
11 | s.screenshots = 'https://raw.githubusercontent.com/D-32/DMSwipeCards/master/Screenshots/01.png', 'https://raw.githubusercontent.com/D-32/DMSwipeCards/master/Screenshots/02.png', 'https://raw.githubusercontent.com/D-32/DMSwipeCards/master/Screenshots/03.png'
12 | s.license = { :type => 'MIT', :file => 'LICENSE' }
13 | s.author = { 'Dylan Marriott' => 'info@d-32.com' }
14 | s.source = { :git => 'https://github.com/d-32/DMSwipeCards.git', :tag => s.version.to_s }
15 | s.social_media_url = 'https://twitter.com/dylan36032'
16 |
17 | s.ios.deployment_target = '8.0'
18 |
19 | s.source_files = 'DMSwipeCards/Classes/**/*'
20 | end
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Dylan Marriott
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards/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 |
--------------------------------------------------------------------------------
/.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 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | ## Playgrounds
31 | timeline.xctimeline
32 | playground.xcworkspace
33 |
34 | # Swift Package Manager
35 | #
36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
37 | # Packages/
38 | .build/
39 |
40 | # CocoaPods
41 | #
42 | # We recommend against adding the Pods directory to your .gitignore. However
43 | # you should judge for yourself, the pros and cons are mentioned at:
44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
45 | #
46 | Pods/
47 | Podfile.lock
48 |
49 | # Carthage
50 | #
51 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
52 | # Carthage/Checkouts
53 |
54 | Carthage/Build
55 |
56 | # fastlane
57 | #
58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
59 | # screenshots whenever they are needed.
60 | # For more information about the recommended setup visit:
61 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
62 |
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 |
68 | .DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://cocoadocs.org/docsets/DMSwipeCards)
2 | 
3 | [](https://twitter.com/dylan36032)
4 |
5 | 
6 |
7 | ## Features
8 |
9 | - Swift 3
10 | - Custom views for the card & overlay
11 | - Generic
12 | - Dynamically add new cards on top or on the bottom
13 | - Lazy view loading
14 |
15 | ## Setup
16 | ```ruby
17 | pod 'DMSwipeCards'
18 | ```
19 |
20 | ## Usage
21 |
22 | First import the module:
23 | ```swift
24 | import DMSwipeCards
25 | ```
26 |
27 | Next create an instance of a `DMSwipeCardsView`:
28 | (`Element` can be your custom model, or just `String`)
29 | ```swift
30 | let swipeView = DMSwipeCardsView(frame: frame,
31 | viewGenerator: viewGenerator,
32 | overlayGenerator: overlayGenerator)
33 | ```
34 | Views get loaded lazy, so you have to provide `DMSwipeCardsView` with a ViewGenerator and optionally an OverlayGenerator.
35 | ```swift
36 | let viewGenerator: (String, CGRect) -> (UIView) = { (element: Element, frame: CGRect) -> (UIView) in
37 | // return a UIView here
38 | }
39 |
40 | let overlayGenerator: (SwipeMode, CGRect) -> (UIView) = { (mode: SwipeMode, frame: CGRect) -> (UIView) in
41 | // return a UIView here
42 | }
43 | ```
44 | ### Adding cards
45 |
46 | To add new cards, just call the `addCards` method with an array of the previously defined `Element`:
47 | ```swift
48 | swipeView.addCards([Element], onTop: true)
49 | ```
50 | ### Delegate
51 |
52 | `DMSwipeCardsView` has a delegate property so you can get informed when a card has been swipped. The delegate has to implement following methods:
53 | ```swift
54 | func swipedLeft(_ object: Any)
55 | func swipedRight(_ object: Any)
56 | func cardTapped(_ object: Any)
57 | func reachedEndOfStack()
58 | ```
59 | The `object` parameter is guarenteed to have the type `Element`. Sadly generics don't work here.
60 |
61 |
62 | ## Example
63 |
64 | For a nice working demo sample, please take a look the [Example](https://github.com/D-32/DMSwipeCards/tree/master/Example) project.
65 | To run the example, first run `pod install` in the `Example` directory.
66 |
67 | ## Credits
68 | Loosly based on [TinderSimpleSwipeCards](https://github.com/cwRichardKim/TinderSimpleSwipeCards)
69 |
70 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // DMSwipeCards
4 | //
5 | // Created by Dylan Marriott on 12/18/2016.
6 | // Copyright (c) 2016 Dylan Marriott. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import DMSwipeCards
11 |
12 | class ViewController: UIViewController {
13 |
14 | private var swipeView: DMSwipeCardsView!
15 | private var count = 0
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | self.view.backgroundColor = UIColor(white: 0.95, alpha: 1.0)
21 |
22 | /*
23 | * In this example we're using `String` as a type.
24 | * You can use DMSwipeCardsView though with any custom class.
25 | */
26 |
27 | let viewGenerator: (String, CGRect) -> (UIView) = { (element: String, frame: CGRect) -> (UIView) in
28 | let container = UIView(frame: CGRect(x: 30, y: 20, width: frame.width - 60, height: frame.height - 40))
29 | let label = UILabel(frame: container.bounds)
30 | label.text = element
31 | label.textAlignment = .center
32 | label.backgroundColor = UIColor.white
33 | label.font = UIFont.systemFont(ofSize: 48, weight: UIFont.Weight.thin)
34 | label.clipsToBounds = true
35 | label.layer.cornerRadius = 16
36 | container.addSubview(label)
37 |
38 | container.layer.shadowRadius = 4
39 | container.layer.shadowOpacity = 1.0
40 | container.layer.shadowColor = UIColor(white: 0.9, alpha: 1.0).cgColor
41 | container.layer.shadowOffset = CGSize(width: 0, height: 0)
42 | container.layer.shouldRasterize = true
43 | container.layer.rasterizationScale = UIScreen.main.scale
44 |
45 | return container
46 | }
47 |
48 | let overlayGenerator: (SwipeMode, CGRect) -> (UIView) = { (mode: SwipeMode, frame: CGRect) -> (UIView) in
49 | let label = UILabel()
50 | label.frame.size = CGSize(width: 100, height: 100)
51 | label.center = CGPoint(x: frame.width / 2, y: frame.height / 2)
52 | label.layer.cornerRadius = label.frame.width / 2
53 | label.backgroundColor = mode == .left ? UIColor.red : UIColor.green
54 | label.clipsToBounds = true
55 | label.text = mode == .left ? "👍" : "👎"
56 | label.font = UIFont.systemFont(ofSize: 24)
57 | label.textAlignment = .center
58 | return label
59 | }
60 |
61 | let frame = CGRect(x: 0, y: 80, width: self.view.frame.width, height: self.view.frame.height - 160)
62 | swipeView = DMSwipeCardsView(frame: frame,
63 | viewGenerator: viewGenerator,
64 | overlayGenerator: overlayGenerator)
65 | swipeView.delegate = self
66 | self.view.addSubview(swipeView)
67 |
68 |
69 |
70 | let button = UIButton(frame: CGRect(x: 0, y: 40, width: self.view.frame.width, height: 40))
71 | button.setTitle("Load cards", for: .normal)
72 | button.setTitleColor(UIColor.blue, for: .normal)
73 | button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
74 | self.view.addSubview(button)
75 | }
76 |
77 | @objc func buttonTapped() {
78 | let ac = UIAlertController(title: "Load on top / on bottom?", message: nil, preferredStyle: .actionSheet)
79 | ac.addAction(UIAlertAction(title: "On Top", style: .default, handler: { (a: UIAlertAction) in
80 | self.swipeView.addCards((self.count...(self.count+3)).map({"\($0)"}), onTop: true)
81 | self.count = self.count + 4
82 | }))
83 | ac.addAction(UIAlertAction(title: "On Bottom", style: .default, handler: { (a: UIAlertAction) in
84 | self.swipeView.addCards((self.count...(self.count+3)).map({"\($0)"}), onTop: false)
85 | self.count = self.count + 4
86 | }))
87 | self.present(ac, animated: true, completion: nil)
88 | }
89 | }
90 |
91 | extension ViewController: DMSwipeCardsViewDelegate {
92 | func swipedLeft(_ object: Any) {
93 | print("Swiped left: \(object)")
94 | }
95 |
96 | func swipedRight(_ object: Any) {
97 | print("Swiped right: \(object)")
98 | }
99 |
100 | func cardTapped(_ object: Any) {
101 | print("Tapped on: \(object)")
102 | }
103 |
104 | func reachedEndOfStack() {
105 | print("Reached end of stack")
106 | }
107 | }
108 |
109 |
--------------------------------------------------------------------------------
/DMSwipeCards/Classes/DMSwipeCardsView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DMSwipeCardsView.swift
3 | // Pods
4 | //
5 | // Created by Dylan Marriott on 18/12/16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | public enum SwipeMode {
13 | case left
14 | case right
15 | }
16 |
17 | public protocol DMSwipeCardsViewDelegate: class {
18 | func swipedLeft(_ object: Any)
19 | func swipedRight(_ object: Any)
20 | func cardTapped(_ object: Any)
21 | func reachedEndOfStack()
22 | }
23 |
24 | public class DMSwipeCardsView: UIView {
25 |
26 | public weak var delegate: DMSwipeCardsViewDelegate?
27 | public var bufferSize: Int = 2
28 |
29 | fileprivate let viewGenerator: ViewGenerator
30 | fileprivate let overlayGenerator: OverlayGenerator?
31 | fileprivate var allCards = [Element]()
32 | fileprivate var loadedCards = [DMSwipeCard]()
33 |
34 | public typealias ViewGenerator = (_ element: Element, _ frame: CGRect) -> (UIView)
35 | public typealias OverlayGenerator = (_ mode: SwipeMode, _ frame: CGRect) -> (UIView)
36 | public init(frame: CGRect,
37 | viewGenerator: @escaping ViewGenerator,
38 | overlayGenerator: OverlayGenerator? = nil) {
39 | self.overlayGenerator = overlayGenerator
40 | self.viewGenerator = viewGenerator
41 | super.init(frame: frame)
42 | self.isUserInteractionEnabled = false
43 | }
44 |
45 | override private init(frame: CGRect) {
46 | fatalError("Please use init(frame:,viewGenerator)")
47 | }
48 |
49 | required public init?(coder aDecoder: NSCoder) {
50 | fatalError("Please use init(frame:,viewGenerator)")
51 | }
52 |
53 | public func addCards(_ elements: [Element], onTop: Bool = false) {
54 | if elements.isEmpty {
55 | return
56 | }
57 |
58 | self.isUserInteractionEnabled = true
59 |
60 | if onTop {
61 | for element in elements.reversed() {
62 | allCards.insert(element, at: 0)
63 | }
64 | } else {
65 | for element in elements {
66 | allCards.append(element)
67 | }
68 | }
69 |
70 | if onTop && loadedCards.count > 0 {
71 | for cv in loadedCards {
72 | cv.removeFromSuperview()
73 | }
74 | loadedCards.removeAll()
75 | }
76 |
77 | for element in elements {
78 | if loadedCards.count < bufferSize {
79 | let cardView = self.createCardView(element: element)
80 | if loadedCards.isEmpty {
81 | self.addSubview(cardView)
82 | } else {
83 | self.insertSubview(cardView, belowSubview: loadedCards.last!)
84 | }
85 | self.loadedCards.append(cardView)
86 | }
87 | }
88 | }
89 |
90 | func swipeTopCardRight() {
91 | // TODO: not yet supported
92 | fatalError("Not yet supported")
93 | }
94 |
95 | func swipeTopCardLeft() {
96 | // TODO: not yet supported
97 | fatalError("Not yet supported")
98 | }
99 | }
100 |
101 | extension DMSwipeCardsView: DMSwipeCardDelegate {
102 | func cardSwipedLeft(_ card: DMSwipeCard) {
103 | self.handleSwipedCard(card)
104 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
105 | self.delegate?.swipedLeft(card.obj)
106 | self.loadNextCard()
107 | }
108 | }
109 |
110 | func cardSwipedRight(_ card: DMSwipeCard) {
111 | self.handleSwipedCard(card)
112 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
113 | self.delegate?.swipedRight(card.obj)
114 | self.loadNextCard()
115 | }
116 | }
117 |
118 | func cardTapped(_ card: DMSwipeCard) {
119 | self.delegate?.cardTapped(card.obj)
120 | }
121 | }
122 |
123 | extension DMSwipeCardsView {
124 | fileprivate func handleSwipedCard(_ card: DMSwipeCard) {
125 | self.loadedCards.removeFirst()
126 | self.allCards.removeFirst()
127 | if self.allCards.isEmpty {
128 | self.isUserInteractionEnabled = false
129 | self.delegate?.reachedEndOfStack()
130 | }
131 | }
132 |
133 | fileprivate func loadNextCard() {
134 | if self.allCards.count - self.loadedCards.count > 0 {
135 | let next = self.allCards[loadedCards.count]
136 | let nextView = self.createCardView(element: next)
137 | let below = self.loadedCards.last!
138 | self.loadedCards.append(nextView)
139 | self.insertSubview(nextView, belowSubview: below)
140 | }
141 | }
142 |
143 | fileprivate func createCardView(element: Element) -> DMSwipeCard {
144 | let cardView = DMSwipeCard(frame: self.bounds)
145 | cardView.delegate = self
146 | cardView.obj = element
147 | let sv = self.viewGenerator(element, cardView.bounds)
148 | cardView.addSubview(sv)
149 | cardView.leftOverlay = self.overlayGenerator?(.left, cardView.bounds)
150 | cardView.rightOverlay = self.overlayGenerator?(.right, cardView.bounds)
151 | cardView.configureOverlays()
152 | return cardView
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/DMSwipeCards/Classes/DMSwipeCard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DMSwipeCard.swift
3 | // Pods
4 | //
5 | // Created by Dylan Marriott on 18/12/16.
6 | //
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | protocol DMSwipeCardDelegate: class {
13 | func cardSwipedLeft(_ card: DMSwipeCard)
14 | func cardSwipedRight(_ card: DMSwipeCard)
15 | func cardTapped(_ card: DMSwipeCard)
16 | }
17 |
18 | class DMSwipeCard: UIView {
19 |
20 | weak var delegate: DMSwipeCardDelegate?
21 | var obj: Any!
22 | var leftOverlay: UIView?
23 | var rightOverlay: UIView?
24 |
25 | private let actionMargin: CGFloat = 120.0
26 | private let rotationStrength: CGFloat = 320.0
27 | private let rotationAngle: CGFloat = CGFloat(Double.pi) / CGFloat(8.0)
28 | private let rotationMax: CGFloat = 1
29 | private let scaleStrength: CGFloat = -2
30 | private let scaleMax: CGFloat = 1.02
31 |
32 | private var xFromCenter: CGFloat = 0.0
33 | private var yFromCenter: CGFloat = 0.0
34 | private var originalPoint = CGPoint.zero
35 |
36 | override init(frame: CGRect) {
37 | super.init(frame: frame)
38 |
39 | let panGesture = UIPanGestureRecognizer(target: self, action: #selector(dragEvent(gesture:)))
40 | panGesture.delegate = self
41 | self.addGestureRecognizer(panGesture)
42 |
43 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapEvent(gesture:)))
44 | tapGesture.delegate = self
45 | self.addGestureRecognizer(tapGesture)
46 | }
47 |
48 | required init?(coder aDecoder: NSCoder) {
49 | fatalError("init(coder:) has not been implemented")
50 | }
51 |
52 | func configureOverlays() {
53 | self.configureOverlay(overlay: self.leftOverlay)
54 | self.configureOverlay(overlay: self.rightOverlay)
55 | }
56 |
57 | private func configureOverlay(overlay: UIView?) {
58 | if let o = overlay {
59 | self.addSubview(o)
60 | o.alpha = 0.0
61 | }
62 | }
63 |
64 | @objc func dragEvent(gesture: UIPanGestureRecognizer) {
65 | xFromCenter = gesture.translation(in: self).x
66 | yFromCenter = gesture.translation(in: self).y
67 |
68 | switch gesture.state {
69 | case .began:
70 | self.originalPoint = self.center
71 | break
72 | case .changed:
73 | let rStrength = min(xFromCenter / self.rotationStrength, rotationMax)
74 | let rAngle = self.rotationAngle * rStrength
75 | let scale = min(1 - fabs(rStrength) / self.scaleStrength, self.scaleMax)
76 | self.center = CGPoint(x: self.originalPoint.x + xFromCenter, y: self.originalPoint.y + yFromCenter)
77 | let transform = CGAffineTransform(rotationAngle: rAngle)
78 | let scaleTransform = transform.scaledBy(x: scale, y: scale)
79 | self.transform = scaleTransform
80 | self.updateOverlay(xFromCenter)
81 | break
82 | case .ended:
83 | self.afterSwipeAction()
84 | break
85 | default:
86 | break
87 | }
88 | }
89 |
90 | @objc func tapEvent(gesture: UITapGestureRecognizer) {
91 | self.delegate?.cardTapped(self)
92 | }
93 |
94 | private func afterSwipeAction() {
95 | if xFromCenter > actionMargin {
96 | self.rightAction()
97 | } else if xFromCenter < -actionMargin {
98 | self.leftAction()
99 | } else {
100 | UIView.animate(withDuration: 0.3) {
101 | self.center = self.originalPoint
102 | self.transform = CGAffineTransform.identity
103 | self.leftOverlay?.alpha = 0.0
104 | self.rightOverlay?.alpha = 0.0
105 | }
106 | }
107 | }
108 |
109 | private func updateOverlay(_ distance: CGFloat) {
110 | var activeOverlay: UIView?
111 | if (distance > 0) {
112 | self.leftOverlay?.alpha = 0.0
113 | activeOverlay = self.rightOverlay
114 | } else {
115 | self.rightOverlay?.alpha = 0.0
116 | activeOverlay = self.leftOverlay
117 | }
118 |
119 | activeOverlay?.alpha = min(fabs(distance)/100, 1.0)
120 | }
121 |
122 | private func rightAction() {
123 | let finishPoint = CGPoint(x: 500, y: 2 * yFromCenter + self.originalPoint.y)
124 | UIView.animate(withDuration: 0.3, animations: {
125 | self.center = finishPoint
126 | }) { _ in
127 | self.removeFromSuperview()
128 | }
129 | self.delegate?.cardSwipedRight(self)
130 | }
131 |
132 | private func leftAction() {
133 | let finishPoint = CGPoint(x: -500, y: 2 * yFromCenter + self.originalPoint.y)
134 | UIView.animate(withDuration: 0.3, animations: {
135 | self.center = finishPoint
136 | }) { _ in
137 | self.removeFromSuperview()
138 | }
139 | self.delegate?.cardSwipedLeft(self)
140 | }
141 | }
142 |
143 | extension DMSwipeCard: UIGestureRecognizerDelegate {
144 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
145 | return true
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards.xcodeproj/xcshareddata/xcschemes/DMSwipeCards-Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
80 |
82 |
88 |
89 |
90 |
91 |
92 |
93 |
99 |
101 |
107 |
108 |
109 |
110 |
112 |
113 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/Example/DMSwipeCards.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; };
11 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD71AFB9204008FA782 /* ViewController.swift */; };
12 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; };
13 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; };
14 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; };
15 | 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* Tests.swift */; };
16 | B9551E26ADF407AE3BB533E3 /* Pods_DMSwipeCards_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A6141AE14A14A9F5D1AC3FA4 /* Pods_DMSwipeCards_Example.framework */; };
17 | F05AED7EF5EAE4550F9249E3 /* Pods_DMSwipeCards_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C879166BF64B71F80EAE783B /* Pods_DMSwipeCards_Tests.framework */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXContainerItemProxy section */
21 | 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */ = {
22 | isa = PBXContainerItemProxy;
23 | containerPortal = 607FACC81AFB9204008FA782 /* Project object */;
24 | proxyType = 1;
25 | remoteGlobalIDString = 607FACCF1AFB9204008FA782;
26 | remoteInfo = DMSwipeCards;
27 | };
28 | /* End PBXContainerItemProxy section */
29 |
30 | /* Begin PBXFileReference section */
31 | 607FACD01AFB9204008FA782 /* DMSwipeCards_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DMSwipeCards_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
33 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
34 | 607FACD71AFB9204008FA782 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
35 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
36 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
37 | 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
38 | 607FACE51AFB9204008FA782 /* DMSwipeCards_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DMSwipeCards_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 607FACEA1AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
40 | 607FACEB1AFB9204008FA782 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; };
41 | 6B1B7896F726F29C923F295F /* Pods-DMSwipeCards_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DMSwipeCards_Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-DMSwipeCards_Tests/Pods-DMSwipeCards_Tests.release.xcconfig"; sourceTree = ""; };
42 | 79D49D4CA52D2D5FAE0A4FB4 /* Pods-DMSwipeCards_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DMSwipeCards_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-DMSwipeCards_Example/Pods-DMSwipeCards_Example.release.xcconfig"; sourceTree = ""; };
43 | 7E72897F699D50996F044DB5 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; };
44 | 8D1421C8DEBC15509002FEE1 /* Pods-DMSwipeCards_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DMSwipeCards_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DMSwipeCards_Example/Pods-DMSwipeCards_Example.debug.xcconfig"; sourceTree = ""; };
45 | A2EE6D2C56338D5D1DFA615C /* DMSwipeCards.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = DMSwipeCards.podspec; path = ../DMSwipeCards.podspec; sourceTree = ""; };
46 | A6141AE14A14A9F5D1AC3FA4 /* Pods_DMSwipeCards_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DMSwipeCards_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
47 | C4D2A18B3C40A0ECA3C6D57A /* Pods-DMSwipeCards_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DMSwipeCards_Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DMSwipeCards_Tests/Pods-DMSwipeCards_Tests.debug.xcconfig"; sourceTree = ""; };
48 | C879166BF64B71F80EAE783B /* Pods_DMSwipeCards_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DMSwipeCards_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
49 | E249F1E20D62FBD95928AFD5 /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 607FACCD1AFB9204008FA782 /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | B9551E26ADF407AE3BB533E3 /* Pods_DMSwipeCards_Example.framework in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | 607FACE21AFB9204008FA782 /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | F05AED7EF5EAE4550F9249E3 /* Pods_DMSwipeCards_Tests.framework in Frameworks */,
66 | );
67 | runOnlyForDeploymentPostprocessing = 0;
68 | };
69 | /* End PBXFrameworksBuildPhase section */
70 |
71 | /* Begin PBXGroup section */
72 | 32BA4B9EE20D09F413AC040A /* Frameworks */ = {
73 | isa = PBXGroup;
74 | children = (
75 | A6141AE14A14A9F5D1AC3FA4 /* Pods_DMSwipeCards_Example.framework */,
76 | C879166BF64B71F80EAE783B /* Pods_DMSwipeCards_Tests.framework */,
77 | );
78 | name = Frameworks;
79 | sourceTree = "";
80 | };
81 | 607FACC71AFB9204008FA782 = {
82 | isa = PBXGroup;
83 | children = (
84 | 607FACF51AFB993E008FA782 /* Podspec Metadata */,
85 | 607FACD21AFB9204008FA782 /* Example for DMSwipeCards */,
86 | 607FACE81AFB9204008FA782 /* Tests */,
87 | 607FACD11AFB9204008FA782 /* Products */,
88 | EA37DEB6265882EFAA40D84C /* Pods */,
89 | 32BA4B9EE20D09F413AC040A /* Frameworks */,
90 | );
91 | sourceTree = "";
92 | };
93 | 607FACD11AFB9204008FA782 /* Products */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 607FACD01AFB9204008FA782 /* DMSwipeCards_Example.app */,
97 | 607FACE51AFB9204008FA782 /* DMSwipeCards_Tests.xctest */,
98 | );
99 | name = Products;
100 | sourceTree = "";
101 | };
102 | 607FACD21AFB9204008FA782 /* Example for DMSwipeCards */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */,
106 | 607FACD71AFB9204008FA782 /* ViewController.swift */,
107 | 607FACD91AFB9204008FA782 /* Main.storyboard */,
108 | 607FACDC1AFB9204008FA782 /* Images.xcassets */,
109 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */,
110 | 607FACD31AFB9204008FA782 /* Supporting Files */,
111 | );
112 | name = "Example for DMSwipeCards";
113 | path = DMSwipeCards;
114 | sourceTree = "";
115 | };
116 | 607FACD31AFB9204008FA782 /* Supporting Files */ = {
117 | isa = PBXGroup;
118 | children = (
119 | 607FACD41AFB9204008FA782 /* Info.plist */,
120 | );
121 | name = "Supporting Files";
122 | sourceTree = "";
123 | };
124 | 607FACE81AFB9204008FA782 /* Tests */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 607FACEB1AFB9204008FA782 /* Tests.swift */,
128 | 607FACE91AFB9204008FA782 /* Supporting Files */,
129 | );
130 | path = Tests;
131 | sourceTree = "";
132 | };
133 | 607FACE91AFB9204008FA782 /* Supporting Files */ = {
134 | isa = PBXGroup;
135 | children = (
136 | 607FACEA1AFB9204008FA782 /* Info.plist */,
137 | );
138 | name = "Supporting Files";
139 | sourceTree = "";
140 | };
141 | 607FACF51AFB993E008FA782 /* Podspec Metadata */ = {
142 | isa = PBXGroup;
143 | children = (
144 | A2EE6D2C56338D5D1DFA615C /* DMSwipeCards.podspec */,
145 | E249F1E20D62FBD95928AFD5 /* README.md */,
146 | 7E72897F699D50996F044DB5 /* LICENSE */,
147 | );
148 | name = "Podspec Metadata";
149 | sourceTree = "";
150 | };
151 | EA37DEB6265882EFAA40D84C /* Pods */ = {
152 | isa = PBXGroup;
153 | children = (
154 | 8D1421C8DEBC15509002FEE1 /* Pods-DMSwipeCards_Example.debug.xcconfig */,
155 | 79D49D4CA52D2D5FAE0A4FB4 /* Pods-DMSwipeCards_Example.release.xcconfig */,
156 | C4D2A18B3C40A0ECA3C6D57A /* Pods-DMSwipeCards_Tests.debug.xcconfig */,
157 | 6B1B7896F726F29C923F295F /* Pods-DMSwipeCards_Tests.release.xcconfig */,
158 | );
159 | name = Pods;
160 | sourceTree = "";
161 | };
162 | /* End PBXGroup section */
163 |
164 | /* Begin PBXNativeTarget section */
165 | 607FACCF1AFB9204008FA782 /* DMSwipeCards_Example */ = {
166 | isa = PBXNativeTarget;
167 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "DMSwipeCards_Example" */;
168 | buildPhases = (
169 | 5A24F9515C27B91824A9A6C6 /* [CP] Check Pods Manifest.lock */,
170 | 607FACCC1AFB9204008FA782 /* Sources */,
171 | 607FACCD1AFB9204008FA782 /* Frameworks */,
172 | 607FACCE1AFB9204008FA782 /* Resources */,
173 | 679E24DDE95367712F71CFC5 /* [CP] Embed Pods Frameworks */,
174 | FDE2D9D4B061700E7C3A8627 /* [CP] Copy Pods Resources */,
175 | );
176 | buildRules = (
177 | );
178 | dependencies = (
179 | );
180 | name = DMSwipeCards_Example;
181 | productName = DMSwipeCards;
182 | productReference = 607FACD01AFB9204008FA782 /* DMSwipeCards_Example.app */;
183 | productType = "com.apple.product-type.application";
184 | };
185 | 607FACE41AFB9204008FA782 /* DMSwipeCards_Tests */ = {
186 | isa = PBXNativeTarget;
187 | buildConfigurationList = 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "DMSwipeCards_Tests" */;
188 | buildPhases = (
189 | 9D48BBB0E8673685D521D64B /* [CP] Check Pods Manifest.lock */,
190 | 607FACE11AFB9204008FA782 /* Sources */,
191 | 607FACE21AFB9204008FA782 /* Frameworks */,
192 | 607FACE31AFB9204008FA782 /* Resources */,
193 | CE573A2FF0A2EAE8295B207A /* [CP] Embed Pods Frameworks */,
194 | BC2B06B9A501516B6782B00E /* [CP] Copy Pods Resources */,
195 | );
196 | buildRules = (
197 | );
198 | dependencies = (
199 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */,
200 | );
201 | name = DMSwipeCards_Tests;
202 | productName = Tests;
203 | productReference = 607FACE51AFB9204008FA782 /* DMSwipeCards_Tests.xctest */;
204 | productType = "com.apple.product-type.bundle.unit-test";
205 | };
206 | /* End PBXNativeTarget section */
207 |
208 | /* Begin PBXProject section */
209 | 607FACC81AFB9204008FA782 /* Project object */ = {
210 | isa = PBXProject;
211 | attributes = {
212 | LastSwiftUpdateCheck = 0720;
213 | LastUpgradeCheck = 0900;
214 | ORGANIZATIONNAME = CocoaPods;
215 | TargetAttributes = {
216 | 607FACCF1AFB9204008FA782 = {
217 | CreatedOnToolsVersion = 6.3.1;
218 | DevelopmentTeam = U69N6KJ99T;
219 | LastSwiftMigration = 0900;
220 | };
221 | 607FACE41AFB9204008FA782 = {
222 | CreatedOnToolsVersion = 6.3.1;
223 | DevelopmentTeam = U69N6KJ99T;
224 | LastSwiftMigration = 0900;
225 | TestTargetID = 607FACCF1AFB9204008FA782;
226 | };
227 | };
228 | };
229 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "DMSwipeCards" */;
230 | compatibilityVersion = "Xcode 3.2";
231 | developmentRegion = English;
232 | hasScannedForEncodings = 0;
233 | knownRegions = (
234 | en,
235 | Base,
236 | );
237 | mainGroup = 607FACC71AFB9204008FA782;
238 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */;
239 | projectDirPath = "";
240 | projectRoot = "";
241 | targets = (
242 | 607FACCF1AFB9204008FA782 /* DMSwipeCards_Example */,
243 | 607FACE41AFB9204008FA782 /* DMSwipeCards_Tests */,
244 | );
245 | };
246 | /* End PBXProject section */
247 |
248 | /* Begin PBXResourcesBuildPhase section */
249 | 607FACCE1AFB9204008FA782 /* Resources */ = {
250 | isa = PBXResourcesBuildPhase;
251 | buildActionMask = 2147483647;
252 | files = (
253 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */,
254 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */,
255 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */,
256 | );
257 | runOnlyForDeploymentPostprocessing = 0;
258 | };
259 | 607FACE31AFB9204008FA782 /* Resources */ = {
260 | isa = PBXResourcesBuildPhase;
261 | buildActionMask = 2147483647;
262 | files = (
263 | );
264 | runOnlyForDeploymentPostprocessing = 0;
265 | };
266 | /* End PBXResourcesBuildPhase section */
267 |
268 | /* Begin PBXShellScriptBuildPhase section */
269 | 5A24F9515C27B91824A9A6C6 /* [CP] Check Pods Manifest.lock */ = {
270 | isa = PBXShellScriptBuildPhase;
271 | buildActionMask = 2147483647;
272 | files = (
273 | );
274 | inputPaths = (
275 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
276 | "${PODS_ROOT}/Manifest.lock",
277 | );
278 | name = "[CP] Check Pods Manifest.lock";
279 | outputPaths = (
280 | "$(DERIVED_FILE_DIR)/Pods-DMSwipeCards_Example-checkManifestLockResult.txt",
281 | );
282 | runOnlyForDeploymentPostprocessing = 0;
283 | shellPath = /bin/sh;
284 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
285 | showEnvVarsInLog = 0;
286 | };
287 | 679E24DDE95367712F71CFC5 /* [CP] Embed Pods Frameworks */ = {
288 | isa = PBXShellScriptBuildPhase;
289 | buildActionMask = 2147483647;
290 | files = (
291 | );
292 | inputPaths = (
293 | "${SRCROOT}/Pods/Target Support Files/Pods-DMSwipeCards_Example/Pods-DMSwipeCards_Example-frameworks.sh",
294 | "${BUILT_PRODUCTS_DIR}/DMSwipeCards/DMSwipeCards.framework",
295 | );
296 | name = "[CP] Embed Pods Frameworks";
297 | outputPaths = (
298 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DMSwipeCards.framework",
299 | );
300 | runOnlyForDeploymentPostprocessing = 0;
301 | shellPath = /bin/sh;
302 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-DMSwipeCards_Example/Pods-DMSwipeCards_Example-frameworks.sh\"\n";
303 | showEnvVarsInLog = 0;
304 | };
305 | 9D48BBB0E8673685D521D64B /* [CP] Check Pods Manifest.lock */ = {
306 | isa = PBXShellScriptBuildPhase;
307 | buildActionMask = 2147483647;
308 | files = (
309 | );
310 | inputPaths = (
311 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
312 | "${PODS_ROOT}/Manifest.lock",
313 | );
314 | name = "[CP] Check Pods Manifest.lock";
315 | outputPaths = (
316 | "$(DERIVED_FILE_DIR)/Pods-DMSwipeCards_Tests-checkManifestLockResult.txt",
317 | );
318 | runOnlyForDeploymentPostprocessing = 0;
319 | shellPath = /bin/sh;
320 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
321 | showEnvVarsInLog = 0;
322 | };
323 | BC2B06B9A501516B6782B00E /* [CP] Copy Pods Resources */ = {
324 | isa = PBXShellScriptBuildPhase;
325 | buildActionMask = 2147483647;
326 | files = (
327 | );
328 | inputPaths = (
329 | );
330 | name = "[CP] Copy Pods Resources";
331 | outputPaths = (
332 | );
333 | runOnlyForDeploymentPostprocessing = 0;
334 | shellPath = /bin/sh;
335 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-DMSwipeCards_Tests/Pods-DMSwipeCards_Tests-resources.sh\"\n";
336 | showEnvVarsInLog = 0;
337 | };
338 | CE573A2FF0A2EAE8295B207A /* [CP] Embed Pods Frameworks */ = {
339 | isa = PBXShellScriptBuildPhase;
340 | buildActionMask = 2147483647;
341 | files = (
342 | );
343 | inputPaths = (
344 | );
345 | name = "[CP] Embed Pods Frameworks";
346 | outputPaths = (
347 | );
348 | runOnlyForDeploymentPostprocessing = 0;
349 | shellPath = /bin/sh;
350 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-DMSwipeCards_Tests/Pods-DMSwipeCards_Tests-frameworks.sh\"\n";
351 | showEnvVarsInLog = 0;
352 | };
353 | FDE2D9D4B061700E7C3A8627 /* [CP] Copy Pods Resources */ = {
354 | isa = PBXShellScriptBuildPhase;
355 | buildActionMask = 2147483647;
356 | files = (
357 | );
358 | inputPaths = (
359 | );
360 | name = "[CP] Copy Pods Resources";
361 | outputPaths = (
362 | );
363 | runOnlyForDeploymentPostprocessing = 0;
364 | shellPath = /bin/sh;
365 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-DMSwipeCards_Example/Pods-DMSwipeCards_Example-resources.sh\"\n";
366 | showEnvVarsInLog = 0;
367 | };
368 | /* End PBXShellScriptBuildPhase section */
369 |
370 | /* Begin PBXSourcesBuildPhase section */
371 | 607FACCC1AFB9204008FA782 /* Sources */ = {
372 | isa = PBXSourcesBuildPhase;
373 | buildActionMask = 2147483647;
374 | files = (
375 | 607FACD81AFB9204008FA782 /* ViewController.swift in Sources */,
376 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */,
377 | );
378 | runOnlyForDeploymentPostprocessing = 0;
379 | };
380 | 607FACE11AFB9204008FA782 /* Sources */ = {
381 | isa = PBXSourcesBuildPhase;
382 | buildActionMask = 2147483647;
383 | files = (
384 | 607FACEC1AFB9204008FA782 /* Tests.swift in Sources */,
385 | );
386 | runOnlyForDeploymentPostprocessing = 0;
387 | };
388 | /* End PBXSourcesBuildPhase section */
389 |
390 | /* Begin PBXTargetDependency section */
391 | 607FACE71AFB9204008FA782 /* PBXTargetDependency */ = {
392 | isa = PBXTargetDependency;
393 | target = 607FACCF1AFB9204008FA782 /* DMSwipeCards_Example */;
394 | targetProxy = 607FACE61AFB9204008FA782 /* PBXContainerItemProxy */;
395 | };
396 | /* End PBXTargetDependency section */
397 |
398 | /* Begin PBXVariantGroup section */
399 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = {
400 | isa = PBXVariantGroup;
401 | children = (
402 | 607FACDA1AFB9204008FA782 /* Base */,
403 | );
404 | name = Main.storyboard;
405 | sourceTree = "";
406 | };
407 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = {
408 | isa = PBXVariantGroup;
409 | children = (
410 | 607FACDF1AFB9204008FA782 /* Base */,
411 | );
412 | name = LaunchScreen.xib;
413 | sourceTree = "";
414 | };
415 | /* End PBXVariantGroup section */
416 |
417 | /* Begin XCBuildConfiguration section */
418 | 607FACED1AFB9204008FA782 /* Debug */ = {
419 | isa = XCBuildConfiguration;
420 | buildSettings = {
421 | ALWAYS_SEARCH_USER_PATHS = NO;
422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
423 | CLANG_CXX_LIBRARY = "libc++";
424 | CLANG_ENABLE_MODULES = YES;
425 | CLANG_ENABLE_OBJC_ARC = YES;
426 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
427 | CLANG_WARN_BOOL_CONVERSION = YES;
428 | CLANG_WARN_COMMA = YES;
429 | CLANG_WARN_CONSTANT_CONVERSION = YES;
430 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
431 | CLANG_WARN_EMPTY_BODY = YES;
432 | CLANG_WARN_ENUM_CONVERSION = YES;
433 | CLANG_WARN_INFINITE_RECURSION = YES;
434 | CLANG_WARN_INT_CONVERSION = YES;
435 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
436 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
437 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
438 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
439 | CLANG_WARN_STRICT_PROTOTYPES = YES;
440 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
441 | CLANG_WARN_UNREACHABLE_CODE = YES;
442 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
443 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
444 | COPY_PHASE_STRIP = NO;
445 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
446 | ENABLE_STRICT_OBJC_MSGSEND = YES;
447 | ENABLE_TESTABILITY = YES;
448 | GCC_C_LANGUAGE_STANDARD = gnu99;
449 | GCC_DYNAMIC_NO_PIC = NO;
450 | GCC_NO_COMMON_BLOCKS = YES;
451 | GCC_OPTIMIZATION_LEVEL = 0;
452 | GCC_PREPROCESSOR_DEFINITIONS = (
453 | "DEBUG=1",
454 | "$(inherited)",
455 | );
456 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
457 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
458 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
459 | GCC_WARN_UNDECLARED_SELECTOR = YES;
460 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
461 | GCC_WARN_UNUSED_FUNCTION = YES;
462 | GCC_WARN_UNUSED_VARIABLE = YES;
463 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
464 | MTL_ENABLE_DEBUG_INFO = YES;
465 | ONLY_ACTIVE_ARCH = YES;
466 | SDKROOT = iphoneos;
467 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
468 | };
469 | name = Debug;
470 | };
471 | 607FACEE1AFB9204008FA782 /* Release */ = {
472 | isa = XCBuildConfiguration;
473 | buildSettings = {
474 | ALWAYS_SEARCH_USER_PATHS = NO;
475 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
476 | CLANG_CXX_LIBRARY = "libc++";
477 | CLANG_ENABLE_MODULES = YES;
478 | CLANG_ENABLE_OBJC_ARC = YES;
479 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
480 | CLANG_WARN_BOOL_CONVERSION = YES;
481 | CLANG_WARN_COMMA = YES;
482 | CLANG_WARN_CONSTANT_CONVERSION = YES;
483 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
484 | CLANG_WARN_EMPTY_BODY = YES;
485 | CLANG_WARN_ENUM_CONVERSION = YES;
486 | CLANG_WARN_INFINITE_RECURSION = YES;
487 | CLANG_WARN_INT_CONVERSION = YES;
488 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
489 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
490 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
491 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
492 | CLANG_WARN_STRICT_PROTOTYPES = YES;
493 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
494 | CLANG_WARN_UNREACHABLE_CODE = YES;
495 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
496 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
497 | COPY_PHASE_STRIP = NO;
498 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
499 | ENABLE_NS_ASSERTIONS = NO;
500 | ENABLE_STRICT_OBJC_MSGSEND = YES;
501 | GCC_C_LANGUAGE_STANDARD = gnu99;
502 | GCC_NO_COMMON_BLOCKS = YES;
503 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
504 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
505 | GCC_WARN_UNDECLARED_SELECTOR = YES;
506 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
507 | GCC_WARN_UNUSED_FUNCTION = YES;
508 | GCC_WARN_UNUSED_VARIABLE = YES;
509 | IPHONEOS_DEPLOYMENT_TARGET = 8.3;
510 | MTL_ENABLE_DEBUG_INFO = NO;
511 | SDKROOT = iphoneos;
512 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
513 | VALIDATE_PRODUCT = YES;
514 | };
515 | name = Release;
516 | };
517 | 607FACF01AFB9204008FA782 /* Debug */ = {
518 | isa = XCBuildConfiguration;
519 | baseConfigurationReference = 8D1421C8DEBC15509002FEE1 /* Pods-DMSwipeCards_Example.debug.xcconfig */;
520 | buildSettings = {
521 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
522 | DEVELOPMENT_TEAM = U69N6KJ99T;
523 | INFOPLIST_FILE = DMSwipeCards/Info.plist;
524 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
525 | MODULE_NAME = ExampleApp;
526 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
527 | PRODUCT_NAME = "$(TARGET_NAME)";
528 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
529 | SWIFT_VERSION = 4.0;
530 | };
531 | name = Debug;
532 | };
533 | 607FACF11AFB9204008FA782 /* Release */ = {
534 | isa = XCBuildConfiguration;
535 | baseConfigurationReference = 79D49D4CA52D2D5FAE0A4FB4 /* Pods-DMSwipeCards_Example.release.xcconfig */;
536 | buildSettings = {
537 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
538 | DEVELOPMENT_TEAM = U69N6KJ99T;
539 | INFOPLIST_FILE = DMSwipeCards/Info.plist;
540 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
541 | MODULE_NAME = ExampleApp;
542 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
543 | PRODUCT_NAME = "$(TARGET_NAME)";
544 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
545 | SWIFT_VERSION = 4.0;
546 | };
547 | name = Release;
548 | };
549 | 607FACF31AFB9204008FA782 /* Debug */ = {
550 | isa = XCBuildConfiguration;
551 | baseConfigurationReference = C4D2A18B3C40A0ECA3C6D57A /* Pods-DMSwipeCards_Tests.debug.xcconfig */;
552 | buildSettings = {
553 | DEVELOPMENT_TEAM = U69N6KJ99T;
554 | FRAMEWORK_SEARCH_PATHS = (
555 | "$(SDKROOT)/Developer/Library/Frameworks",
556 | "$(inherited)",
557 | );
558 | GCC_PREPROCESSOR_DEFINITIONS = (
559 | "DEBUG=1",
560 | "$(inherited)",
561 | );
562 | INFOPLIST_FILE = Tests/Info.plist;
563 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
564 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
565 | PRODUCT_NAME = "$(TARGET_NAME)";
566 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
567 | SWIFT_VERSION = 4.0;
568 | };
569 | name = Debug;
570 | };
571 | 607FACF41AFB9204008FA782 /* Release */ = {
572 | isa = XCBuildConfiguration;
573 | baseConfigurationReference = 6B1B7896F726F29C923F295F /* Pods-DMSwipeCards_Tests.release.xcconfig */;
574 | buildSettings = {
575 | DEVELOPMENT_TEAM = U69N6KJ99T;
576 | FRAMEWORK_SEARCH_PATHS = (
577 | "$(SDKROOT)/Developer/Library/Frameworks",
578 | "$(inherited)",
579 | );
580 | INFOPLIST_FILE = Tests/Info.plist;
581 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
582 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
583 | PRODUCT_NAME = "$(TARGET_NAME)";
584 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
585 | SWIFT_VERSION = 4.0;
586 | };
587 | name = Release;
588 | };
589 | /* End XCBuildConfiguration section */
590 |
591 | /* Begin XCConfigurationList section */
592 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "DMSwipeCards" */ = {
593 | isa = XCConfigurationList;
594 | buildConfigurations = (
595 | 607FACED1AFB9204008FA782 /* Debug */,
596 | 607FACEE1AFB9204008FA782 /* Release */,
597 | );
598 | defaultConfigurationIsVisible = 0;
599 | defaultConfigurationName = Release;
600 | };
601 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "DMSwipeCards_Example" */ = {
602 | isa = XCConfigurationList;
603 | buildConfigurations = (
604 | 607FACF01AFB9204008FA782 /* Debug */,
605 | 607FACF11AFB9204008FA782 /* Release */,
606 | );
607 | defaultConfigurationIsVisible = 0;
608 | defaultConfigurationName = Release;
609 | };
610 | 607FACF21AFB9204008FA782 /* Build configuration list for PBXNativeTarget "DMSwipeCards_Tests" */ = {
611 | isa = XCConfigurationList;
612 | buildConfigurations = (
613 | 607FACF31AFB9204008FA782 /* Debug */,
614 | 607FACF41AFB9204008FA782 /* Release */,
615 | );
616 | defaultConfigurationIsVisible = 0;
617 | defaultConfigurationName = Release;
618 | };
619 | /* End XCConfigurationList section */
620 | };
621 | rootObject = 607FACC81AFB9204008FA782 /* Project object */;
622 | }
623 |
--------------------------------------------------------------------------------