Skip to content
Snippets Groups Projects
Commit 4249191b authored by Bruno Muniz's avatar Bruno Muniz :apple:
Browse files

Fixes scrolling of nickname drawer

parent a25859e9
No related branches found
No related tags found
1 merge request!100Fixes scrolling of nickname drawer
...@@ -226,6 +226,10 @@ let package = Package( ...@@ -226,6 +226,10 @@ let package = Package(
name: "XXModels", name: "XXModels",
package: "client-ios-db" package: "client-ios-db"
), ),
.product(
name: "ScrollViewController",
package: "ScrollViewController"
),
.product( .product(
name: "Dependencies", name: "Dependencies",
package: "swift-composable-architecture" package: "swift-composable-architecture"
......
import UIKit import UIKit
import Combine
final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning { final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning {
enum Direction { enum Direction {
...@@ -9,11 +8,10 @@ final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning { ...@@ -9,11 +8,10 @@ final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning {
let isDismissableOnBackground: Bool let isDismissableOnBackground: Bool
var direction: Direction = .present var direction: Direction = .present
private let onDismissal: (() -> Void)? private let onDismissal: () -> Void
private weak var darkOverlayView: UIControl? private weak var darkOverlayView: UIControl?
private weak var topConstraint: NSLayoutConstraint? private weak var topConstraint: NSLayoutConstraint?
private weak var bottomConstraint: NSLayoutConstraint? private weak var bottomConstraint: NSLayoutConstraint?
private var cancellables = Set<AnyCancellable>()
private var presentedConstraints: [NSLayoutConstraint] = [] private var presentedConstraints: [NSLayoutConstraint] = []
private var dismissedConstraints: [NSLayoutConstraint] = [] private var dismissedConstraints: [NSLayoutConstraint] = []
...@@ -21,7 +19,7 @@ final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning { ...@@ -21,7 +19,7 @@ final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning {
init( init(
_ isDismissableOnBackground: Bool = true, _ isDismissableOnBackground: Bool = true,
onDismissal: (() -> Void)? onDismissal: @escaping () -> Void
) { ) {
self.onDismissal = onDismissal self.onDismissal = onDismissal
self.isDismissableOnBackground = isDismissableOnBackground self.isDismissableOnBackground = isDismissableOnBackground
...@@ -123,7 +121,7 @@ final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning { ...@@ -123,7 +121,7 @@ final class BottomTransition: NSObject, UIViewControllerAnimatedTransitioning {
}, },
completion: { [weak self] _ in completion: { [weak self] _ in
context.completeTransition(true) context.completeTransition(true)
self?.onDismissal?() self?.onDismissal()
} }
) )
} }
......
...@@ -23,3 +23,26 @@ final class BottomTransitioningDelegate: NSObject, UIViewControllerTransitioning ...@@ -23,3 +23,26 @@ final class BottomTransitioningDelegate: NSObject, UIViewControllerTransitioning
return transition return transition
} }
} }
final class FullscreenTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
private var transition: FullscreenTransition?
func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
transition = FullscreenTransition { [weak self] in
guard let self else { return }
self.transition = nil
}
return transition
}
func animationController(
forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
transition?.direction = .dismiss
return transition
}
}
import UIKit
final class FullscreenTransition: NSObject, UIViewControllerAnimatedTransitioning {
enum Direction {
case present
case dismiss
}
var direction: Direction = .present
private let onDismissal: () -> Void
private weak var darkOverlayView: UIControl?
private weak var topConstraint: NSLayoutConstraint?
private weak var bottomConstraint: NSLayoutConstraint?
private var presentedConstraints: [NSLayoutConstraint] = []
private var dismissedConstraints: [NSLayoutConstraint] = []
private var presentingController: UIViewController?
init(onDismissal: @escaping () -> Void) {
self.onDismissal = onDismissal
super.init()
}
func transitionDuration(
using context: UIViewControllerContextTransitioning?
) -> TimeInterval { 0.5 }
func animateTransition(
using context: UIViewControllerContextTransitioning
) {
switch direction {
case .present:
present(using: context)
case .dismiss:
dismiss(using: context)
}
}
private func present(using context: UIViewControllerContextTransitioning) {
guard let presentingController = context.viewController(forKey: .from),
let presentedView = context.view(forKey: .to) else {
context.completeTransition(false)
return
}
let darkOverlayView = UIControl()
self.darkOverlayView = darkOverlayView
darkOverlayView.alpha = 0.0
darkOverlayView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
context.containerView.addSubview(darkOverlayView)
darkOverlayView.frame = context.containerView.bounds
darkOverlayView.addTarget(self, action: #selector(didTapOverlay), for: .touchUpInside)
self.presentingController = presentingController
context.containerView.addSubview(presentedView)
presentedView.translatesAutoresizingMaskIntoConstraints = false
presentedConstraints = [
presentedView.topAnchor.constraint(equalTo: context.containerView.topAnchor),
presentedView.leftAnchor.constraint(equalTo: context.containerView.leftAnchor),
presentedView.rightAnchor.constraint(equalTo: context.containerView.rightAnchor),
presentedView.bottomAnchor.constraint(equalTo: context.containerView.bottomAnchor)
]
dismissedConstraints = [
presentedView.leftAnchor.constraint(equalTo: context.containerView.leftAnchor),
presentedView.rightAnchor.constraint(equalTo: context.containerView.rightAnchor),
presentedView.topAnchor.constraint(equalTo: context.containerView.bottomAnchor),
presentedView.heightAnchor.constraint(equalTo: context.containerView.heightAnchor)
]
NSLayoutConstraint.activate(dismissedConstraints)
context.containerView.setNeedsLayout()
context.containerView.layoutIfNeeded()
NSLayoutConstraint.deactivate(dismissedConstraints)
NSLayoutConstraint.activate(presentedConstraints)
UIView.animate(
withDuration: transitionDuration(using: context),
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 0,
options: .curveEaseInOut,
animations: {
darkOverlayView.alpha = 1.0
context.containerView.setNeedsLayout()
context.containerView.layoutIfNeeded()
},
completion: { _ in
context.completeTransition(true)
})
}
private func dismiss(using context: UIViewControllerContextTransitioning) {
NSLayoutConstraint.deactivate(presentedConstraints)
NSLayoutConstraint.activate(dismissedConstraints)
UIView.animate(
withDuration: transitionDuration(using: context),
delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 0,
options: .curveEaseInOut,
animations: { [weak darkOverlayView] in
darkOverlayView?.alpha = 0.0
context.containerView.setNeedsLayout()
context.containerView.layoutIfNeeded()
},
completion: { [weak self] _ in
context.completeTransition(true)
self?.onDismissal()
})
}
@objc private func didTapOverlay() {
if let presentingController {
presentingController.dismiss(animated: true)
}
}
}
import UIKit import UIKit
import ScrollViewController
/// Opens up `Nickname` on a given parent view controller /// Opens up `Nickname` on a given parent view controller
public struct PresentNickname: Action { public struct PresentNickname: Action {
...@@ -35,27 +36,31 @@ public struct PresentNickname: Action { ...@@ -35,27 +36,31 @@ public struct PresentNickname: Action {
/// Performs `PresentNickname` action /// Performs `PresentNickname` action
public struct PresentNicknameNavigator: TypedNavigator { public struct PresentNicknameNavigator: TypedNavigator {
/// Custom transitioning delegate /// Custom transitioning delegate
let transitioningDelegate = BottomTransitioningDelegate() let transitioningDelegate = FullscreenTransitioningDelegate()
/// View controller which should be opened up /// View controller which should be opened up
var viewController: (String, @escaping (String) -> Void) -> UIViewController var viewController: (String, @escaping (String) -> Void) -> UIViewController
/// - Parameters: /// - Parameters:
/// - viewController: view controller which should be presented /// - viewController: view controller which should be presented
public init(_ viewController: @escaping ( public init(_ viewController: @escaping (String, @escaping (String) -> Void) -> UIViewController) {
String, @escaping (String) -> Void
) -> UIViewController
) {
self.viewController = viewController self.viewController = viewController
} }
public func perform(_ action: PresentNickname, completion: @escaping () -> Void) { public func perform(_ action: PresentNickname, completion: @escaping () -> Void) {
let scrollViewController = ScrollViewController()
let controller = viewController(action.prefilled, action.completion) let controller = viewController(action.prefilled, action.completion)
scrollViewController.addChild(controller)
scrollViewController.contentView = controller.view
scrollViewController.wrapperView.handlesTouchesOutsideContent = true
scrollViewController.wrapperView.alignContentToBottom = true
scrollViewController.scrollView.bounces = false
controller.didMove(toParent: scrollViewController)
controller.transitioningDelegate = transitioningDelegate controller.transitioningDelegate = transitioningDelegate
controller.modalPresentationStyle = .overFullScreen scrollViewController.modalPresentationStyle = .overFullScreen
action.parent.present( action.parent.present(
controller, scrollViewController,
animated: action.animated, animated: action.animated,
completion: completion completion: completion
) )
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment