Я пытаюсь представить модально представление при нажатии на кнопку, которое будет иметь сначала тот же кадр, что и кнопка, а затем развернется до полного экрана, все это с помощью UIViewControllerTransitioningDelegate
.
Вот мой код:
Расширяемая база
class ExpandableBase: UIViewController {
var senderFrame: CGRect = .zero
@IBOutlet weak var fullScreenPopupView: UIView?
@IBAction func dismiss() {
self.dismiss(animated: true, completion: nil)
}
}
Расширение переходного делегата
extension ExpandableBase: UIViewControllerTransitioningDelegate {
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return ExpandableBasePresenter()
}
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return ExpandableBaseDismisser()
}
}
private final class ExpandableBasePresenter: NSObject, UIViewControllerAnimatedTransitioning {
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.8
}
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let toViewController: ExpandableBase = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! ExpandableBase
let duration = self.transitionDuration(using: transitionContext)
let containerView = transitionContext.containerView
toViewController.view.frame = containerView.frame
containerView.addSubview(toViewController.view)
let finishFrame = toViewController.fullScreenPopupView?.frame
toViewController.fullScreenPopupView?.frame = toViewController.senderFrame
UIView.animate(withDuration: duration, delay: 0.3, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: .layoutSubviews, animations: {
toViewController.fullScreenPopupView?.frame = finishFrame!
}) { result in
transitionContext.completeTransition(result)
}
}
}
private final class ExpandableBaseDismisser: NSObject, UIViewControllerAnimatedTransitioning {
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.4
}
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let fromViewController: ExpandableBase = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! ExpandableBase
let duration = self.transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, delay: 0.1, usingSpringWithDamping: 1.0, initialSpringVelocity: 0.0, options: .layoutSubviews, animations: {
fromViewController.fullScreenPopupView?.frame = fromViewController.senderFrame
}) { result in
transitionContext.completeTransition(result)
}
}
}
Простое представление с использованиемэто, представляя этикетку и кнопку отклонения:
final class ExpandableSimpleView: ExpandableBase {
init(from initialFrame: CGRect) {
super.init(nibName: "ExpandableSimpleView", bundle: .main)
self.senderFrame = initialFrame
self.transitioningDelegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("NOPE")
}
static func present(fromInitialFrame initialFrame: CGRect) {
let expandableSimpleView = ExpandableSimpleView(from: initialFrame)
expandableSimpleView.modalPresentationStyle = .overCurrentContext
AppDelegateTopMostViewController.present(expandableSimpleView, animated: true, completion: nil)
//AppDelegateTopMostViewController is a global reference to the top-most view controller of the app
}
}
Вот соответствующий XIB:
И как я представляюэто из родительского контроллера представления:
@IBAction func openSimpleView(_ sender: UIButton) {
ExpandableSimpleView.present(fromInitialFrame: sender.frame)
}
И вот несколько скриншотов, показывающих, как расширяется это представление:
Хотяпредставление расширяется нормально, метка не центрирована, как должно быть.Я не понимаю, почему.
Спасибо за вашу помощь.
РЕДАКТИРОВАТЬ : следуя ответу Мэтта, я внес следующие изменения в докладчика animateTransition
,
toViewController.fullScreenPopupView!.transform =
toViewController.fullScreenPopupView!.transform.scaledBy(x: toViewController.senderFrame.width / toViewController.view.bounds.width, y: toViewController.senderFrame.height / toViewController.view.bounds.height)
UIView.animate(withDuration: duration, delay: 0, options: [.allowUserInteraction], animations: {
toViewController.fullScreenPopupView!.transform = .identity
}, completion: nil)
Теперь анимация в порядке, но я столкнулся с другой проблемой: кнопка в представлении больше не активируется.