From f2f6cb5aac8327877630dd458f5c3676a37fb39b Mon Sep 17 00:00:00 2001 From: Leandro Linardos Date: Sun, 8 Aug 2021 10:59:33 -0300 Subject: [PATCH] Add option, disabled by default to avoid retro-compability issues. Add rubber band effect. Add demo. --- Demos/DemoControllers/RubberBandDemo.swift | 35 ++++++++++++++++++++++ Demos/ModalDemosViewController.swift | 3 +- FittedSheets.xcodeproj/project.pbxproj | 4 +++ FittedSheets/SheetOptions.swift | 6 +++- FittedSheets/SheetViewController.swift | 13 ++++++-- 5 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 Demos/DemoControllers/RubberBandDemo.swift diff --git a/Demos/DemoControllers/RubberBandDemo.swift b/Demos/DemoControllers/RubberBandDemo.swift new file mode 100644 index 0000000..1561979 --- /dev/null +++ b/Demos/DemoControllers/RubberBandDemo.swift @@ -0,0 +1,35 @@ +// +// RubberBandDemo.swift +// Demos +// +// Created by Leandro Linardos on 08/08/2021. +// Copyright © 2021 Gordon Tucker. All rights reserved. +// + +import UIKit +import FittedSheets + +class RubberBandDemo: SimpleDemo { + override class var name: String { "Rubber Band" } + + override class func openDemo(from parent: UIViewController, in view: UIView?) { + let useInlineMode = view != nil + + let controller = ColorDemo() + + let sheet = SheetViewController( + controller: controller, + sizes: [.fixed(150), .fixed(350)], + options: SheetOptions(useInlineMode: useInlineMode, isRubberBandEnabled: true)) + sheet.allowPullingPastMaxHeight = false + sheet.allowPullingPastMinHeight = false + + addSheetEventLogging(to: sheet) + + if let view = view { + sheet.animateIn(to: view, in: parent) + } else { + parent.present(sheet, animated: true, completion: nil) + } + } +} diff --git a/Demos/ModalDemosViewController.swift b/Demos/ModalDemosViewController.swift index 4a16c4e..cacf13a 100644 --- a/Demos/ModalDemosViewController.swift +++ b/Demos/ModalDemosViewController.swift @@ -33,7 +33,8 @@ class ModalDemosViewController: UIViewController { HorizontalPaddingDemo.self, MaxWidthDemo.self, BlurDemo.self, - NestedSheetsDemo.self + NestedSheetsDemo.self, + RubberBandDemo.self ].sorted(by: { $0.name < $1.name }) override func viewDidLoad() { diff --git a/FittedSheets.xcodeproj/project.pbxproj b/FittedSheets.xcodeproj/project.pbxproj index 14d6fd1..34044c6 100644 --- a/FittedSheets.xcodeproj/project.pbxproj +++ b/FittedSheets.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0D18902926C015F700CB6790 /* RubberBandDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D18902826C015F700CB6790 /* RubberBandDemo.swift */; }; C4E231E524E55E4E00D367FD /* BlurDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4E231E424E55E4E00D367FD /* BlurDemo.swift */; }; F8034165212625DD00EAD717 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8034164212625DD00EAD717 /* AppDelegate.swift */; }; F803416A212625DD00EAD717 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F8034168212625DD00EAD717 /* Main.storyboard */; }; @@ -99,6 +100,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0D18902826C015F700CB6790 /* RubberBandDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RubberBandDemo.swift; sourceTree = ""; }; 46334410249C041700F334E5 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; C4E231E424E55E4E00D367FD /* BlurDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurDemo.swift; sourceTree = ""; }; F8034161212625DD00EAD717 /* Demos.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demos.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -302,6 +304,7 @@ F857D0A62204B856004C862F /* SimpleDemo.swift */, F8799C9925BF5EB70095F24F /* ColorDemo.swift */, F8A42B7624D9FD3D005DE55B /* NestedSheetsDemo.swift */, + 0D18902826C015F700CB6790 /* RubberBandDemo.swift */, F83058D925BF688300EE17E1 /* NoPullBarDemo.swift */, F8A42B7A24D9FFBE005DE55B /* ClearPullBarDemo.swift */, F8A42B5F24D36DE3005DE55B /* MapDemo.swift */, @@ -476,6 +479,7 @@ F8A42B8C24DB1A67005DE55B /* InlineDemosViewController.swift in Sources */, F8A42B6024D36DE3005DE55B /* MapDemo.swift in Sources */, F8A42B8424DA022F005DE55B /* OnlyCloseWithButtonDemo.swift in Sources */, + 0D18902926C015F700CB6790 /* RubberBandDemo.swift in Sources */, F83058FD25BF777400EE17E1 /* SlideInAnimationBug118TagCell.swift in Sources */, F857D0AE2204D709004C862F /* TableViewDemo.swift in Sources */, F8FAC6B925A3930F0042A307 /* MaxWidthDemo.swift in Sources */, diff --git a/FittedSheets/SheetOptions.swift b/FittedSheets/SheetOptions.swift index f6dd612..cc311e3 100644 --- a/FittedSheets/SheetOptions.swift +++ b/FittedSheets/SheetOptions.swift @@ -57,6 +57,8 @@ public struct SheetOptions { @available(*, unavailable, message: "cornerRadius is now a property on SheetViewController") public var cornerRadius: CGFloat = 0 + + public var isRubberBandEnabled: Bool = false public init() { } public init(pullBarHeight: CGFloat? = nil, @@ -67,7 +69,8 @@ public struct SheetOptions { shrinkPresentingViewController: Bool? = nil, useInlineMode: Bool? = nil, horizontalPadding: CGFloat? = nil, - maxWidth: CGFloat? = nil) { + maxWidth: CGFloat? = nil, + isRubberBandEnabled: Bool? = nil) { let defaultOptions = SheetOptions.default self.pullBarHeight = pullBarHeight ?? defaultOptions.pullBarHeight self.presentingViewCornerRadius = presentingViewCornerRadius ?? defaultOptions.presentingViewCornerRadius @@ -79,6 +82,7 @@ public struct SheetOptions { self.horizontalPadding = horizontalPadding ?? defaultOptions.horizontalPadding let maxWidth = maxWidth ?? defaultOptions.maxWidth self.maxWidth = maxWidth == 0 ? nil : maxWidth + self.isRubberBandEnabled = isRubberBandEnabled ?? false } @available(*, unavailable, message: "cornerRadius, minimumSpaceAbovePullBar, gripSize and gripColor are now properties on SheetViewController. Use them instead.") diff --git a/FittedSheets/SheetViewController.swift b/FittedSheets/SheetViewController.swift index 46d5dac..fda4d1a 100644 --- a/FittedSheets/SheetViewController.swift +++ b/FittedSheets/SheetViewController.swift @@ -374,7 +374,11 @@ public class SheetViewController: UIViewController { newHeight = minHeight } if newHeight > maxHeight { - newHeight = maxHeight + if options.isRubberBandEnabled { + newHeight = logConstraintValueForYPosition(verticalLimit: maxHeight, yPosition: newHeight) + } else { + newHeight = maxHeight + } } switch gesture.state { @@ -478,7 +482,7 @@ public class SheetViewController: UIViewController { break // Do nothing } } - + private func registerKeyboardObservers() { NotificationCenter.default.addObserver(self, selector: #selector(keyboardShown(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardDismissed(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) @@ -534,6 +538,11 @@ public class SheetViewController: UIViewController { } return min(fullscreenHeight, contentHeight) } + + // https://medium.com/thoughts-on-thoughts/recreating-apple-s-rubber-band-effect-in-swift-dbf981b40f35 + private func logConstraintValueForYPosition(verticalLimit: CGFloat, yPosition : CGFloat) -> CGFloat { + return verticalLimit * (1 + log10(yPosition/verticalLimit)) + } public func resize(to size: SheetSize, duration: TimeInterval = 0.2,