Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow dynamic full expansion behaviour #103

Merged
merged 2 commits into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions DrawerKit/DrawerKit/Internal API/AnimationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ extension AnimationController: UIViewControllerAnimatedTransitioning {
presentingVC: presentingVC,
presentedVC: presentedVC)

let drawerFullY = (presentedVC as? DrawerPresentable)?.fullExpansionBehaviour?.drawerFullY
?? configuration.fullExpansionBehaviour.drawerFullY

let drawerPartialH = (presentedVC as? DrawerPresentable)?.heightOfPartiallyExpandedDrawer ?? 0
let partialH = GeometryEvaluator.drawerPartialH(drawerPartialHeight: drawerPartialH,
containerViewHeight: containerViewH)
Expand All @@ -55,17 +58,23 @@ extension AnimationController: UIViewControllerAnimatedTransitioning {
let collapsedH = GeometryEvaluator.drawerPartialH(drawerPartialHeight: drawerCollapsedH,
containerViewHeight: containerViewH)

let startDrawerState = GeometryEvaluator.drawerState(for: initialFrame.origin.y,
drawerCollapsedHeight: collapsedH,
drawerPartialHeight: partialH,
containerViewHeight: containerViewH,
configuration: configuration)

let targetDrawerState = GeometryEvaluator.drawerState(for: finalFrame.origin.y,
drawerCollapsedHeight: collapsedH,
drawerPartialHeight: partialH,
containerViewHeight: containerViewH,
configuration: configuration)
let startDrawerState = GeometryEvaluator.drawerState(
for: initialFrame.origin.y,
drawerFullY: drawerFullY,
drawerCollapsedHeight: collapsedH,
drawerPartialHeight: partialH,
containerViewHeight: containerViewH,
configuration: configuration
)

let targetDrawerState = GeometryEvaluator.drawerState(
for: finalFrame.origin.y,
drawerFullY: drawerFullY,
drawerCollapsedHeight: collapsedH,
drawerPartialHeight: partialH,
containerViewHeight: containerViewH,
configuration: configuration
)

let info = AnimationSupport.makeInfo(startDrawerState: startDrawerState,
targetDrawerState: targetDrawerState,
Expand Down
25 changes: 15 additions & 10 deletions DrawerKit/DrawerKit/Internal API/GeometryEvaluator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ struct GeometryEvaluator {
return containerViewHeight - collapsedH
}

static func upperMarkY(drawerPartialHeight: CGFloat,
containerViewHeight: CGFloat,
configuration: DrawerConfiguration) -> CGFloat {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
static func upperMarkY(
drawerFullY: CGFloat,
drawerPartialHeight: CGFloat,
containerViewHeight: CGFloat,
configuration: DrawerConfiguration
) -> CGFloat {
let partialY = drawerPartialY(drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight)
return max(partialY - configuration.upperMarkGap, drawerFullY)
Expand All @@ -43,11 +45,12 @@ struct GeometryEvaluator {
}

static func clamped(_ positionY: CGFloat,
drawerFullY: CGFloat,
drawerPartialHeight: CGFloat,
containerViewHeight: CGFloat,
configuration: DrawerConfiguration) -> CGFloat {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
let upperY = upperMarkY(drawerPartialHeight: drawerPartialHeight,
let upperY = upperMarkY(drawerFullY: drawerFullY,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration)
if smallerThanOrEqual(positionY, upperY) {
Expand All @@ -73,12 +76,12 @@ struct GeometryEvaluator {

extension GeometryEvaluator {
static func drawerState(for positionY: CGFloat,
drawerFullY: CGFloat,
drawerCollapsedHeight: CGFloat,
drawerPartialHeight: CGFloat,
containerViewHeight: CGFloat,
configuration: DrawerConfiguration,
clampToNearest: Bool = false) -> DrawerState {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
if smallerThanOrEqual(positionY, drawerFullY) { return .fullyExpanded }
if greaterThanOrEqual(positionY, containerViewHeight) { return .dismissed }

Expand All @@ -92,10 +95,12 @@ extension GeometryEvaluator {

if clampToNearest {
let posY = clamped(positionY,
drawerFullY: drawerFullY,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration)
return drawerState(for: posY,
drawerFullY: drawerFullY,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
Expand Down Expand Up @@ -128,6 +133,7 @@ extension GeometryEvaluator {

static func nextStateFrom(currentState: DrawerState,
speedY: CGFloat,
drawerFullY: CGFloat,
drawerCollapsedHeight: CGFloat,
drawerPartialHeight: CGFloat,
containerViewHeight: CGFloat,
Expand All @@ -141,15 +147,14 @@ extension GeometryEvaluator {
let isMovingUpQuickly = isMovingUp && isMovingQuickly
let isMovingDownQuickly = isMovingDown && isMovingQuickly

let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY

let positionY = drawerPositionY(for: currentState,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
drawerFullY: drawerFullY)

let upperY = upperMarkY(drawerPartialHeight: drawerPartialHeight,
let upperY = upperMarkY(drawerFullY: drawerFullY,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,14 @@ extension PresentationController {
}

if endingPosition != .end {
self.targetDrawerState = GeometryEvaluator.drawerState(for: self.currentDrawerY,
drawerCollapsedHeight: self.drawerCollapsedHeight,
drawerPartialHeight: self.drawerPartialY,
containerViewHeight: self.containerViewHeight,
configuration: self.configuration)
self.targetDrawerState = GeometryEvaluator.drawerState(
for: self.currentDrawerY,
drawerFullY: self.drawerFullY,
drawerCollapsedHeight: self.drawerCollapsedHeight,
drawerPartialHeight: self.drawerPartialY,
containerViewHeight: self.containerViewHeight,
configuration: self.configuration
)
}

AnimationSupport.clientCleanupViews(presentingDrawerAnimationActions: presentingAnimationActions,
Expand All @@ -110,7 +113,6 @@ extension PresentationController {
}

func addCornerRadiusAnimationEnding(at endingState: DrawerState) {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
guard maximumCornerRadius != 0
&& drawerPartialY != drawerFullY
&& endingState != currentDrawerState
Expand Down Expand Up @@ -162,7 +164,6 @@ extension PresentationController {

private func positionsY(startingState: DrawerState,
endingState: DrawerState) -> (starting: CGFloat, ending: CGFloat) {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
let startingPositionY =
GeometryEvaluator.drawerPositionY(for: startingState,
drawerCollapsedHeight: drawerCollapsedHeight,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ extension PresentationController {

case .ended:
let drawerSpeedY = panGesture.velocity(in: view).y / containerViewHeight
let endingState = GeometryEvaluator.nextStateFrom(currentState: currentDrawerState,
speedY: drawerSpeedY,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration)
let endingState = GeometryEvaluator.nextStateFrom(
currentState: currentDrawerState,
speedY: drawerSpeedY,
drawerFullY: drawerFullY,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration
)
animateTransition(to: endingState)

case .cancelled:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ extension PresentationController {
return containerViewSize.height
}

var drawerFullY: CGFloat {
return (presentedViewController as? DrawerPresentable)?.fullExpansionBehaviour?.drawerFullY
?? configuration.fullExpansionBehaviour.drawerFullY
}

var drawerPartialHeight: CGFloat {
guard let presentedVC = presentedViewController as? DrawerPresentable else { return 0 }
let drawerPartialH = presentedVC.heightOfPartiallyExpandedDrawer
Expand All @@ -38,7 +43,8 @@ extension PresentationController {
}

var upperMarkY: CGFloat {
return GeometryEvaluator.upperMarkY(drawerPartialHeight: drawerPartialHeight,
return GeometryEvaluator.upperMarkY(drawerFullY: drawerFullY,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration)
}
Expand All @@ -52,14 +58,14 @@ extension PresentationController {
var currentDrawerState: DrawerState {
get {
return GeometryEvaluator.drawerState(for: currentDrawerY,
drawerFullY: drawerFullY,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
configuration: configuration)
}

set {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
currentDrawerY =
GeometryEvaluator.drawerPositionY(for: newValue,
drawerCollapsedHeight: drawerCollapsedHeight,
Expand All @@ -71,13 +77,11 @@ extension PresentationController {

var currentDrawerY: CGFloat {
get {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
let posY = presentedView?.frame.origin.y ?? drawerFullY
return min(max(posY, drawerFullY), containerViewHeight)
}

set {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
let posY = min(max(newValue, drawerFullY), containerViewHeight)
presentedView?.frame.origin.y = posY
}
Expand Down Expand Up @@ -113,16 +117,15 @@ extension PresentationController {
case .maximumAtPartialY:
return maximumCornerRadius * triangularValue(at: state)
case .alwaysShowBelowStatusBar:
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
let positionY =
GeometryEvaluator.drawerPositionY(for: state,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
drawerFullY: drawerFullY)
let positionY = GeometryEvaluator.drawerPositionY(
for: state,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
containerViewHeight: containerViewHeight,
drawerFullY: drawerFullY
)

return maximumCornerRadius * min(positionY, DrawerGeometry.statusBarHeight) / DrawerGeometry.statusBarHeight

}
}

Expand All @@ -131,7 +134,6 @@ extension PresentationController {
}

private func triangularValue(at state: DrawerState) -> CGFloat {
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
guard drawerPartialY != drawerFullY
&& drawerPartialY != containerViewHeight
&& drawerFullY != containerViewHeight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,15 @@ final class PullToDismissManager: NSObject, UIScrollViewDelegate {
}

let drawerSpeedY = -velocity.y / presentationController.containerViewHeight
let endingState = GeometryEvaluator.nextStateFrom(currentState: presentationController.currentDrawerState,
speedY: drawerSpeedY,
drawerCollapsedHeight: presentationController.drawerCollapsedHeight,
drawerPartialHeight: presentationController.drawerPartialHeight,
containerViewHeight: presentationController.containerViewHeight,
configuration: presentationController.configuration)
let endingState = GeometryEvaluator.nextStateFrom(
currentState: presentationController.currentDrawerState,
speedY: drawerSpeedY,
drawerFullY: presentationController.drawerFullY,
drawerCollapsedHeight: presentationController.drawerCollapsedHeight,
drawerPartialHeight: presentationController.drawerPartialHeight,
containerViewHeight: presentationController.containerViewHeight,
configuration: presentationController.configuration
)

presentationController.animateTransition(
to: endingState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ extension PresentationController {
var frame: CGRect = .zero
frame.size = size(forChildContentContainer: presentedViewController,
withParentContainerSize: containerViewSize)
let drawerFullY = configuration.fullExpansionBehaviour.drawerFullY
frame.origin.y = GeometryEvaluator.drawerPositionY(for: targetDrawerState,
drawerCollapsedHeight: drawerCollapsedHeight,
drawerPartialHeight: drawerPartialHeight,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@ public protocol DrawerPresentable: class {
/// collapsed state. If negative, its value is clamped to zero.
/// Default implementation returns 0.
var heightOfCollapsedDrawer: CGFloat { get }

/// Whether the drawer expands to cover the entire screen, the entire screen minus
/// the status bar, or the entire screen minus a custom gap. If this property
/// returns `nil` then the value of `fullExpansionBehaviour` in the `DrawerConfiguration`
/// will be used instead. The default is `nil`.
var fullExpansionBehaviour: DrawerConfiguration.FullExpansionBehaviour? { get }
}

public extension DrawerPresentable {
var heightOfCollapsedDrawer: CGFloat { return 0 }
var fullExpansionBehaviour: DrawerConfiguration.FullExpansionBehaviour? { return nil }
}
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ public struct DrawerConfiguration {

/// Whether the drawer expands to cover the entire screen, the entire screen minus
/// the status bar, or the entire screen minus a custom gap. The default is to cover
/// the full screen.
/// the full screen. If presented view controller conforms to the DrawerPresentable
/// the value that it returns from `fullExpansionBehaviour` will be used instead,
/// unless it is `nil`.
public var fullExpansionBehaviour: FullExpansionBehaviour

/// When `true`, the drawer is presented first in its partially expanded state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ extension PresentedNavigationController: DrawerPresentable {
var heightOfPartiallyExpandedDrawer: CGFloat {
return (topViewController as? DrawerPresentable)?.heightOfPartiallyExpandedDrawer ?? 0.0
}

var fullExpansionBehaviour: DrawerConfiguration.FullExpansionBehaviour? {
return (topViewController as? DrawerPresentable)?.fullExpansionBehaviour
}
}

extension PresentedNavigationController: UINavigationControllerDelegate {
Expand Down
4 changes: 4 additions & 0 deletions DrawerKitDemo/DrawerKitDemo/PresentedViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ extension PresentedViewController: DrawerPresentable {

// var heightOfCollapsedDrawer: CGFloat {
// return 100
// }

// var fullExpansionBehaviour: DrawerConfiguration.FullExpansionBehaviour? {
// return .leavesCustomGap(gap: 100)
// }

var heightOfPartiallyExpandedDrawer: CGFloat {
Expand Down