diff --git a/.gitignore b/.gitignore index 624ccbf..83d8cf9 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ DerivedData *.ipa *.xcuserstate .DS_Store +.swiftpm # CocoaPods # diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..f262591 --- /dev/null +++ b/Package.swift @@ -0,0 +1,23 @@ +// swift-tools-version:5.5 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "ZLSwipeableViewSwift", + platforms: [.iOS(.v13)], + products: [ + .library( + name: "ZLSwipeableViewSwift", + targets: ["ZLSwipeableViewSwift"]), + ], + dependencies: [], + targets: [ + .target( + name: "ZLSwipeableViewSwift", + dependencies: [], + path: "ZLSwipeableViewSwift", + exclude: ["Info.plist"] + ), + ] +) diff --git a/README.md b/README.md index 7e1d694..13154dc 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,16 @@ Carthage --- You can install `ZLSwipeableViewSwift` through Carthage by adding `github "zhxnlai/ZLSwipeableViewSwift"` to your Cartfile +Swift Package Manager +--- +You can install `ZLSwipeableViewSwift` through Swift Package Manager by adding it to the `dependencies` value of your `Package.swift`. + +```swift +dependencies: [ + .package(url: "https://github.com/zhxnlai/ZLSwipeableViewSwift", .branchItem("master")) +] +``` + Usage --- Check out the [demo app](https://github.com/zhxnlai/ZLSwipeableViewSwift/archive/master.zip) for an example. It contains the following demos: Default, Custom Animation, Custom Swipe, Allowed Direction, History, Previous View, Should Swipe and Always Swipe. @@ -136,6 +146,7 @@ Here is a list of customizable behaviors: public var animateView = ZLSwipeableView.defaultAnimateViewHandler() public var interpretDirection = ZLSwipeableView.defaultInterpretDirectionHandler() public var shouldSwipeView = ZLSwipeableView.defaultShouldSwipeViewHandler() +public var angle = CGFloat(1.0) public var minTranslationInPercent = CGFloat(0.25) public var minVelocityInPointPerSecond = CGFloat(750) public var allowedDirection = Direction.Horizontal @@ -157,6 +168,10 @@ swipeableView.allowedDirection = .Left | .Up swipeableView.allowedDirection = .All ~~~ +### angle + +You can change the rotation of the swipe views with the 'angle' property + ### Misc ~~~swift diff --git a/ZLSwipeableViewSwift.podspec b/ZLSwipeableViewSwift.podspec index 3de0a16..8d579ca 100644 --- a/ZLSwipeableViewSwift.podspec +++ b/ZLSwipeableViewSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "ZLSwipeableViewSwift" - s.version = "0.0.8" + s.version = "0.0.9" s.summary = "A simple view for building card like interface like Tinder and Potluck." s.description = <<-DESC ZLSwipeableViewSwift is a simple view for building card like interface like Tinder and Potluck. @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.platform = :ios, "8.0" - s.source = { :git => "https://github.com/zhxnlai/ZLSwipeableViewSwift.git", :tag => "0.0.8" } + s.source = { :git => "https://github.com/zhxnlai/ZLSwipeableViewSwift.git", :tag => "0.0.9" } s.source_files = "ZLSwipeableViewSwift/*.swift" s.framework = "UIKit" diff --git a/ZLSwipeableViewSwift/ViewManager.swift b/ZLSwipeableViewSwift/ViewManager.swift index 0da6332..dda72e5 100644 --- a/ZLSwipeableViewSwift/ViewManager.swift +++ b/ZLSwipeableViewSwift/ViewManager.swift @@ -143,7 +143,14 @@ class ViewManager : NSObject { } func addTapRecognizer() { - guard !(view.gestureRecognizers ?? []).contains(where: { $0 is ZLTapGestureRecognizer }) else { return } + for gesture in view.gestureRecognizers ?? [] { + if let tapGesture = gesture as? ZLTapGestureRecognizer { + + // Remove previous tap gesture + view.removeGestureRecognizer(tapGesture) + + } + } view.addGestureRecognizer(ZLTapGestureRecognizer(target: self, action: #selector(ViewManager.handleTap(_:)))) } @@ -166,6 +173,13 @@ class ViewManager : NSObject { removeBehavior(snapBehavior) } + func resnapView() { + if case .snapping(_) = state { + unsnapView() + state = snappingStateAtContainerCenter() + } + } + fileprivate func attachView(toPoint point: CGPoint) { anchorView.center = point anchorView.backgroundColor = UIColor.blue diff --git a/ZLSwipeableViewSwift/ZLSwipeableView.swift b/ZLSwipeableViewSwift/ZLSwipeableView.swift index 7c4eab5..075b59f 100644 --- a/ZLSwipeableViewSwift/ZLSwipeableView.swift +++ b/ZLSwipeableViewSwift/ZLSwipeableView.swift @@ -51,6 +51,7 @@ open class ZLSwipeableView: UIView { open var animateView = ZLSwipeableView.defaultAnimateViewHandler() open var interpretDirection = ZLSwipeableView.defaultInterpretDirectionHandler() open var shouldSwipeView = ZLSwipeableView.defaultShouldSwipeViewHandler() + open var angle = CGFloat(1.0) open var minTranslationInPercent = CGFloat(0.25) open var minVelocityInPointPerSecond = CGFloat(750) open var allowedDirection = Direction.Horizontal @@ -117,6 +118,9 @@ open class ZLSwipeableView: UIView { override open func layoutSubviews() { super.layoutSubviews() containerView.frame = bounds + for viewManager in viewManagers.values { + viewManager.resnapView() + } } // MARK: Public APIs @@ -262,7 +266,7 @@ extension ZLSwipeableView { static func defaultAnimateViewHandler() -> AnimateViewHandler { func toRadian(_ degree: CGFloat) -> CGFloat { - return degree * CGFloat(M_PI / 180) + return degree * CGFloat(Double.pi / 180) } func rotateView(_ view: UIView, forDegree degree: CGFloat, duration: TimeInterval, offsetFromCenter offset: CGPoint, swipeableView: ZLSwipeableView, completion: ((Bool) -> Void)? = nil) { @@ -277,7 +281,7 @@ extension ZLSwipeableView { } return { (view: UIView, index: Int, views: [UIView], swipeableView: ZLSwipeableView) in - let degree = CGFloat(1) + let degree = swipeableView.angle let duration = 0.4 let offset = CGPoint(x: 0, y: swipeableView.bounds.height * 0.3) switch index { @@ -347,51 +351,6 @@ extension ZLSwipeableView { } -// MARK: - Deprecated APIs -extension ZLSwipeableView { - - @available(*, deprecated: 1, message: "Use numberOfActiveView") - public var numPrefetchedViews: UInt { - get { - return numberOfActiveView - } - set(newValue){ - numberOfActiveView = newValue - } - } - - @available(*, deprecated: 1, message: "Use allowedDirection") - public var direction: Direction { - get { - return allowedDirection - } - set(newValue){ - allowedDirection = newValue - } - } - - @available(*, deprecated: 1, message: "Use minTranslationInPercent") - public var translationThreshold: CGFloat { - get { - return minTranslationInPercent - } - set(newValue){ - minTranslationInPercent = newValue - } - } - - @available(*, deprecated: 1, message: "Use minVelocityInPointPerSecond") - public var velocityThreshold: CGFloat { - get { - return minVelocityInPointPerSecond - } - set(newValue){ - minVelocityInPointPerSecond = newValue - } - } - -} - // MARK: - Helper extensions public func *(lhs: CGPoint, rhs: CGFloat) -> CGPoint { return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs) diff --git a/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/Constrain.swift b/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/Constrain.swift index 8dd1418..b5f2a28 100644 --- a/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/Constrain.swift +++ b/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/Constrain.swift @@ -141,6 +141,6 @@ import Foundation /// /// - parameter clear: The `ConstraintGroup` whose constraints should be removed. /// -@discardableResult public func constrain(clear group: ConstraintGroup) { +public func constrain(clear group: ConstraintGroup) { group.replaceConstraints([]) } diff --git a/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/LayoutSupport.swift b/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/LayoutSupport.swift index bb9b160..f680564 100644 --- a/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/LayoutSupport.swift +++ b/ZLSwipeableViewSwiftDemo/Pods/Cartography/Cartography/LayoutSupport.swift @@ -18,13 +18,13 @@ import Foundation public extension UIViewController { - public var topLayoutGuideCartography : LayoutSupport { + var topLayoutGuideCartography : LayoutSupport { get { return LayoutSupport(layoutGuide: self.topLayoutGuide, attribute: .bottom) } } - public var bottomLayoutGuideCartography : LayoutSupport { + var bottomLayoutGuideCartography : LayoutSupport { get { return LayoutSupport(layoutGuide: self.bottomLayoutGuide, attribute: .top) } diff --git a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo.xcodeproj/project.pbxproj b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo.xcodeproj/project.pbxproj index 1c5748d..0b43cc8 100644 --- a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo.xcodeproj/project.pbxproj +++ b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo.xcodeproj/project.pbxproj @@ -251,12 +251,11 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 1100; ORGANIZATIONNAME = "Zhixuan Lai"; TargetAttributes = { 09673A7D1AEF5B2E008C7240 = { CreatedOnToolsVersion = 6.3.1; - DevelopmentTeam = NAV5A3CB56; LastSwiftMigration = 0900; }; 09673A921AEF5B2E008C7240 = { @@ -271,6 +270,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -457,17 +457,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -502,17 +513,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -531,6 +553,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.3; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; VALIDATE_PRODUCT = YES; }; name = Release; @@ -539,14 +562,15 @@ isa = XCBuildConfiguration; baseConfigurationReference = 4BA34855EB4A4C2074C86E94 /* Pods-ZLSwipeableViewSwiftDemo.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = NAV5A3CB56; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ZLSwipeableViewSwiftDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.axcel.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -554,14 +578,15 @@ isa = XCBuildConfiguration; baseConfigurationReference = 4AEF23DC622C3A7E809F3742 /* Pods-ZLSwipeableViewSwiftDemo.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = NAV5A3CB56; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = ZLSwipeableViewSwiftDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.axcel.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -569,7 +594,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = E98741382FDFBC754EDA0B1E /* Pods-ZLSwipeableViewSwiftDemoTests.debug.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -583,7 +610,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.axcel.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZLSwipeableViewSwiftDemo.app/ZLSwipeableViewSwiftDemo"; }; name = Debug; @@ -592,7 +619,9 @@ isa = XCBuildConfiguration; baseConfigurationReference = C998BF9C49543ECF772E8671 /* Pods-ZLSwipeableViewSwiftDemoTests.release.xcconfig */; buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO; BUNDLE_LOADER = "$(TEST_HOST)"; + DEVELOPMENT_TEAM = ""; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)/Developer/Library/Frameworks", "$(inherited)", @@ -602,7 +631,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.axcel.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ZLSwipeableViewSwiftDemo.app/ZLSwipeableViewSwiftDemo"; }; name = Release; diff --git a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/AppDelegate.swift b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/AppDelegate.swift index 4970e66..49542a7 100644 --- a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/AppDelegate.swift +++ b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/AppDelegate.swift @@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) if let window = window { let menuViewController = MenuTableViewController(style: .grouped) diff --git a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/CustomAnimationDemoViewController.swift b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/CustomAnimationDemoViewController.swift index e27d495..5798e94 100644 --- a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/CustomAnimationDemoViewController.swift +++ b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/CustomAnimationDemoViewController.swift @@ -13,7 +13,7 @@ class CustomAnimationDemoViewController: ZLSwipeableViewController { override func viewDidLoad() { super.viewDidLoad() func toRadian(_ degree: CGFloat) -> CGFloat { - return degree * CGFloat(M_PI/180) + return degree * CGFloat(Double.pi/180) } func rotateAndTranslateView(_ view: UIView, forDegree degree: CGFloat, translation: CGPoint, duration: TimeInterval, offsetFromCenter offset: CGPoint, swipeableView: ZLSwipeableView) { UIView.animate(withDuration: duration, delay: 0, options: .allowUserInteraction, animations: { diff --git a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/PreviousViewDemoViewController.swift b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/PreviousViewDemoViewController.swift index 10d33b9..dc04094 100644 --- a/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/PreviousViewDemoViewController.swift +++ b/ZLSwipeableViewSwiftDemo/ZLSwipeableViewSwiftDemo/PreviousViewDemoViewController.swift @@ -33,6 +33,11 @@ class PreviousViewDemoViewController: ZLSwipeableViewController { // ↺ let rightBarButtonItem = UIBarButtonItem(title: rightBarButtonItemTitle, style: .plain, target: self, action: #selector(rightBarButtonClicked)) navigationItem.rightBarButtonItem = rightBarButtonItem + + // Load previous by tap the card +// swipeableView.didTap = {view, location in +// self.swipeableView.rewind() +// } } func applyRandomTansform(_ view: UIView) { @@ -41,7 +46,7 @@ class PreviousViewDemoViewController: ZLSwipeableViewController { let distance = max(width, height) func randomRadian() -> CGFloat { - return CGFloat(arc4random() % 360) * CGFloat(M_PI / 180) + return CGFloat(arc4random() % 360) * CGFloat(Double.pi / 180) } var transform = CGAffineTransform(rotationAngle: randomRadian())