Skip to content

Commit

Permalink
support interactions on presented view
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyapuchka committed Oct 24, 2018
1 parent 6edf4eb commit 92b5013
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 16 deletions.
4 changes: 4 additions & 0 deletions DrawerKit/DrawerKit.xcodeproj/project.pbxproj
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
654604CE207BD4BC00B72395 /* DrawerPresentationControlling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654604CD207BD4BC00B72395 /* DrawerPresentationControlling.swift */; };
9A158BC22076C92200FD4113 /* PresentationController+PullToDismiss.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A158BC12076C92200FD4113 /* PresentationController+PullToDismiss.swift */; };
B5D4058C21811B77000B3349 /* PresentationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D4058B21811B77000B3349 /* PresentationContainerView.swift */; };
CB1B6DF31FC346CC006C1F89 /* DrawerShadowConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1B6DF21FC346CC006C1F89 /* DrawerShadowConfiguration.swift */; };
CB1B6E011FC8629B006C1F89 /* DrawerBorderConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1B6E001FC8629B006C1F89 /* DrawerBorderConfiguration.swift */; };
CB2CB7941F8E934500AA152D /* DrawerPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2CB78D1F8E934500AA152D /* DrawerPresentable.swift */; };
Expand Down Expand Up @@ -44,6 +45,7 @@
/* Begin PBXFileReference section */
654604CD207BD4BC00B72395 /* DrawerPresentationControlling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawerPresentationControlling.swift; sourceTree = "<group>"; };
9A158BC12076C92200FD4113 /* PresentationController+PullToDismiss.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PresentationController+PullToDismiss.swift"; sourceTree = "<group>"; };
B5D4058B21811B77000B3349 /* PresentationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationContainerView.swift; sourceTree = "<group>"; };
CB1B6DF21FC346CC006C1F89 /* DrawerShadowConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerShadowConfiguration.swift; sourceTree = "<group>"; };
CB1B6E001FC8629B006C1F89 /* DrawerBorderConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerBorderConfiguration.swift; sourceTree = "<group>"; };
CB2CB78D1F8E934500AA152D /* DrawerPresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawerPresentable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -118,6 +120,7 @@
CB2CB79C1F8E951900AA152D /* AnimationController.swift */,
CBFA36F11F9C4004006847BB /* GeometryEvaluator.swift */,
CBACF6B21F9C622300C15CA3 /* AnimationSupport.swift */,
B5D4058B21811B77000B3349 /* PresentationContainerView.swift */,
);
path = "Internal API";
sourceTree = "<group>";
Expand Down Expand Up @@ -268,6 +271,7 @@
CB5AF8061F9BE0E3000B2DC9 /* DrawerGeometry.swift in Sources */,
CB5AF8021F9BDF29000B2DC9 /* DrawerAnimationActions.swift in Sources */,
CB2CB7941F8E934500AA152D /* DrawerPresentable.swift in Sources */,
B5D4058C21811B77000B3349 /* PresentationContainerView.swift in Sources */,
CB3CAFC01FB24BD800AD28A1 /* Notifications.swift in Sources */,
CB5AF8001F9BDAC5000B2DC9 /* DrawerAnimationParticipant.swift in Sources */,
CB619CEC1F8FFBAD0076E1DE /* InteractionController.swift in Sources */,
Expand Down
34 changes: 34 additions & 0 deletions DrawerKit/DrawerKit/Internal API/PresentationContainerView.swift
@@ -0,0 +1,34 @@
import UIKit

public struct PassthroughOptions: OptionSet {
public let rawValue: Int

public init(rawValue: Int) {
self.rawValue = rawValue
}

public static let collapsed = PassthroughOptions(rawValue: 1 << 0)
public static let partiallyExpanded = PassthroughOptions(rawValue: 1 << 1)
public static let fullyExpanded = PassthroughOptions(rawValue: 1 << 2)
public static let all: PassthroughOptions = [.collapsed, .partiallyExpanded, .fullyExpanded]
}

protocol PresentationContainerViewDelegate: class {
func view(_ view: PresentationContainerView, shouldPassthroughTouchAt point: CGPoint) -> Bool
func view(_ view: PresentationContainerView, forTouchAt point: CGPoint) -> UIView?
}

class PresentationContainerView: UIView {
weak var touchDelegate: PresentationContainerViewDelegate?

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
guard let touchDelegate = touchDelegate,
touchDelegate.view(self, shouldPassthroughTouchAt: point),
let viewForTouch = touchDelegate.view(self, forTouchAt: point) else {
return super.hitTest(point, with: event)
}

let pointInView = viewForTouch.convert(point, from: self)
return viewForTouch.hitTest(pointInView, with: event)
}
}
@@ -1,5 +1,28 @@
import UIKit

extension PresentationController {
func setupPresentationContainerView() {
guard self.presentationContainerView == nil else { return }

let presentationContainerView = PresentationContainerView()
presentationContainerView.touchDelegate = self
presentationContainerView.backgroundColor = .clear
presentationContainerView.frame = containerView?.superview?.frame ?? .zero
presentationContainerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

if let containerView = containerView {
containerView.superview?.addSubview(presentationContainerView)
presentationContainerView.addSubview(containerView)
}

self.presentationContainerView = presentationContainerView
}

func removePresentationContainerView() {
presentationContainerView.removeFromSuperview()
}
}

extension PresentationController {
func setupDrawerFullExpansionTapRecogniser() {
guard drawerFullExpansionTapGR == nil else { return }
Expand Down
24 changes: 24 additions & 0 deletions DrawerKit/DrawerKit/Internal API/PresentationController.swift
Expand Up @@ -5,6 +5,8 @@ final class PresentationController: UIPresentationController {
let inDebugMode: Bool
let handleView: UIView?

var presentationContainerView: PresentationContainerView!

let presentingDrawerAnimationActions: DrawerAnimationActions
let presentedDrawerAnimationActions: DrawerAnimationActions

Expand Down Expand Up @@ -75,7 +77,26 @@ final class PresentationController: UIPresentationController {
}
}

extension PresentationController: PresentationContainerViewDelegate {
func view(_ view: PresentationContainerView, shouldPassthroughTouchAt point: CGPoint) -> Bool {
guard let presentedView = presentedView else { return false }
return !presentedView.bounds.contains(presentedView.convert(point, from: view))
}

func view(_ view: PresentationContainerView, forTouchAt point: CGPoint) -> UIView? {
switch currentDrawerState {
case .fullyExpanded where configuration.passthroughTouchesInStates.contains(.fullyExpanded),
.partiallyExpanded where configuration.passthroughTouchesInStates.contains(.partiallyExpanded),
.collapsed where configuration.passthroughTouchesInStates.contains(.collapsed):
return presentingViewController.view
default:
return containerView
}
}
}

extension PresentationController {

override var frameOfPresentedViewInContainerView: CGRect {
var frame: CGRect = .zero
frame.size = size(forChildContentContainer: presentedViewController,
Expand All @@ -89,6 +110,8 @@ extension PresentationController {
}

override func presentationTransitionWillBegin() {
setupPresentationContainerView()

// NOTE: `targetDrawerState.didSet` is not invoked within the
// initializer.
gestureAvailabilityConditionsDidChange()
Expand Down Expand Up @@ -119,6 +142,7 @@ extension PresentationController {
}

override func dismissalTransitionDidEnd(_ completed: Bool) {
removePresentationContainerView()
removeDrawerFullExpansionTapRecogniser()
removeDrawerDismissalTapRecogniser()
removeDrawerDragRecogniser()
Expand Down
Expand Up @@ -157,6 +157,10 @@ public struct DrawerConfiguration {
/// property to `nil` so as not to have a drawer shadow. The default value is `nil`.
public var drawerShadowConfiguration: DrawerShadowConfiguration?

/// In what states touches should be passed through to the presenting view.
/// By default touches will not be passed through only in `fullyExpanded` state.
public var passthroughTouchesInStates: PassthroughOptions

public init(totalDurationInSeconds: TimeInterval = 0.4,
durationIsProportionalToDistanceTraveled: Bool = false,
timingCurveProvider: UITimingCurveProvider = UISpringTimingParameters(),
Expand All @@ -175,7 +179,8 @@ public struct DrawerConfiguration {
cornerAnimationOption: CornerAnimationOption = .maximumAtPartialY,
handleViewConfiguration: HandleViewConfiguration? = HandleViewConfiguration(),
drawerBorderConfiguration: DrawerBorderConfiguration? = nil,
drawerShadowConfiguration: DrawerShadowConfiguration? = nil) {
drawerShadowConfiguration: DrawerShadowConfiguration? = nil,
passthroughTouchesInStates: PassthroughOptions = [.collapsed, .partiallyExpanded]) {
self.totalDurationInSeconds = (totalDurationInSeconds > 0 ? totalDurationInSeconds : 0.4)
self.durationIsProportionalToDistanceTraveled = durationIsProportionalToDistanceTraveled
self.timingCurveProvider = timingCurveProvider
Expand All @@ -202,6 +207,7 @@ public struct DrawerConfiguration {
self.handleViewConfiguration = handleViewConfiguration
self.drawerBorderConfiguration = drawerBorderConfiguration
self.drawerShadowConfiguration = drawerShadowConfiguration
self.passthroughTouchesInStates = passthroughTouchesInStates
}
}

Expand Down
17 changes: 14 additions & 3 deletions DrawerKitDemo/DrawerKitDemo/PresenterViewController.swift
Expand Up @@ -5,12 +5,22 @@ class PresenterViewController: UIViewController, DrawerCoordinating {
/* strong */ var drawerDisplayController: DrawerDisplayController?

@IBAction func presentButtonTapped() {
doModalPresentation()
doModalPresentation(passthrough: false)
}

@IBAction func presentButtonDoubleTapped() {
doModalPresentation(passthrough: true)
}

@IBAction func alertButtonTapped() {
let alert = UIAlertController(title: "Alert", message: "", preferredStyle: .alert)
alert.addAction(UIAlertAction.init(title: "OK", style: .default, handler: nil))
self.presentedViewController?.present(alert, animated: true, completion: nil)
}
}

private extension PresenterViewController {
func doModalPresentation() {
func doModalPresentation(passthrough: Bool) {
guard let vc = storyboard?.instantiateViewController(withIdentifier: "presented")
as? PresentedNavigationController else { return }

Expand All @@ -25,7 +35,7 @@ private extension PresenterViewController {
configuration.durationIsProportionalToDistanceTraveled = false
// default is UISpringTimingParameters()
configuration.timingCurveProvider = UISpringTimingParameters(dampingRatio: 0.8)
configuration.fullExpansionBehaviour = .coversFullScreen
configuration.fullExpansionBehaviour = .leavesCustomGap(gap: 150)
configuration.supportsPartialExpansion = true
configuration.dismissesInStages = true
configuration.isDrawerDraggable = true
Expand All @@ -37,6 +47,7 @@ private extension PresenterViewController {
configuration.upperMarkGap = 100 // default is 40
configuration.lowerMarkGap = 80 // default is 40
configuration.maximumCornerRadius = 15
configuration.passthroughTouchesInStates = passthrough ? [.collapsed, .partiallyExpanded] : []

var handleViewConfiguration = HandleViewConfiguration()
handleViewConfiguration.autoAnimatesDimming = true
Expand Down

0 comments on commit 92b5013

Please sign in to comment.