90 lines
3.0 KiB
Swift
90 lines
3.0 KiB
Swift
//
|
|
// SheetContainerViewController.swift
|
|
// SheetImagePicker
|
|
//
|
|
// Created by Shadowfacts on 9/23/19.
|
|
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
public class SheetContainerViewController: UIViewController {
|
|
|
|
let content: UIViewController
|
|
|
|
public var detents: [Detent] = [.bottom, .middle, .top] {
|
|
didSet {
|
|
|
|
}
|
|
}
|
|
|
|
var topConstraint: NSLayoutConstraint!
|
|
lazy var initialConstant: CGFloat = view.bounds.height / 2
|
|
|
|
public init(content: UIViewController) {
|
|
self.content = content
|
|
|
|
super.init(nibName: nil, bundle: nil)
|
|
}
|
|
|
|
required public init?(coder: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override public func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
addChild(content)
|
|
content.didMove(toParent: self)
|
|
view.addSubview(content.view)
|
|
topConstraint = content.view.topAnchor.constraint(equalTo: view.topAnchor, constant: initialConstant)
|
|
NSLayoutConstraint.activate([
|
|
content.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
content.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
topConstraint,
|
|
content.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
|
|
])
|
|
|
|
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGestureRecognized(_:)))
|
|
content.view.addGestureRecognizer(panGesture)
|
|
}
|
|
|
|
@objc func panGestureRecognized(_ recognizer: UIPanGestureRecognizer) {
|
|
switch recognizer.state {
|
|
case .began:
|
|
initialConstant = topConstraint.constant
|
|
|
|
case .changed:
|
|
let translation = recognizer.translation(in: content.view)
|
|
var realOffset = initialConstant + translation.y
|
|
if realOffset < view.safeAreaInsets.top {
|
|
print(realOffset)
|
|
realOffset = view.safeAreaInsets.top - realOffset / pow(CGFloat(M_E), realOffset / view.safeAreaInsets.top)
|
|
}
|
|
topConstraint.constant = realOffset
|
|
|
|
case .ended:
|
|
if let offset = nearestDetentOffset(offset: topConstraint.constant) {
|
|
let distance = abs(topConstraint.constant - offset)
|
|
self.topConstraint.constant = offset
|
|
let velocity = recognizer.velocity(in: view)
|
|
let springVelocity = velocity.y / distance
|
|
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: springVelocity, animations: {
|
|
self.view.layoutIfNeeded()
|
|
})
|
|
}
|
|
|
|
default:
|
|
return
|
|
}
|
|
}
|
|
|
|
func nearestDetentOffset(offset: CGFloat) -> CGFloat? {
|
|
return detents.map { $0.offset(in: view) }.min { (a, b) -> Bool in
|
|
return abs(offset - a) < abs(offset - b)
|
|
}
|
|
}
|
|
|
|
}
|
|
|