gpt4 book ai didi

iOS 13 风格的 UIPresentationController 不依赖快照?

转载 作者:行者123 更新时间:2023-11-28 13:33:13 25 4
gpt4 key购买 nike

iOS 13 似乎使用了一个新的 UIPresentationController 来呈现模态视图 Controller ,但它不依赖于拍摄呈现 View Controller 的快照(正如大多数/所有库所做的那样)。当模态视图 Controller 显示在透明/有色背景上方时,呈现 View Controller 是“实时的”并继续显示动画/更改。

我可以通过在呈现 View Controller 的 View 上使用 CGAffineTransform 轻松复制它(因为目的是为 iOS 10/11/12 等制作向后兼容的版本),但是在旋转设备时,呈现的 View 经常开始变形并超出边界,这似乎是因为系统更新了它的 frame,同时应用了一个事件的 transform

根据文档,frame 在对 View 应用 transform 时未定义。鉴于系统似乎正在修改框架而不是我,我该如何解决这个问题而不会在我更新呈现 View 的边界时得到 hacky 解决方案?我需要此呈现 Controller 保持通用,因为呈现 Controller 可以是任何形状或形式,不一定是全屏 View 。

这是我目前所拥有的 - 它是一个简单的 UIPresentationController 子类,它似乎工作正常,但是旋转设备然后关闭呈现的 View Controller 似乎会改变呈现 View Controller 的边界(变得太宽或缩小,具体取决于您是在横向/纵向模式下呈现模态 Controller )

class SheetPresentationController: UIPresentationController {
override var frameOfPresentedViewInContainerView: CGRect {
return CGRect(x: 40, y: containerView!.bounds.height / 2, width: containerView!.bounds.width-80, height: containerView!.bounds.height / 2)
}

override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()

if let _ = presentingViewController.transitionCoordinator {
// We're transitioning - don't touch the frame yet as it'll
// clash with our transform
} else {
self.presentedView?.frame = self.frameOfPresentedViewInContainerView
}
}

override func presentationTransitionWillBegin() {
super.presentationTransitionWillBegin()

containerView?.backgroundColor = .clear

if let coordinator = presentingViewController.transitionCoordinator {
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.containerView?.backgroundColor = UIColor.black.withAlphaComponent(0.3)

// Scale the presenting view
self?.presentingViewController.view.layer.cornerRadius = 16

self?.presentingViewController.view.transform = CGAffineTransform.init(scaleX: 0.9, y: 0.9)
}, completion: nil)
}
}

override func dismissalTransitionWillBegin() {
if let coordinator = presentingViewController.transitionCoordinator {
coordinator.animate(alongsideTransition: { [weak self] _ in
self?.containerView?.backgroundColor = .clear

self?.presentingViewController.view.layer.cornerRadius = 0
self?.presentingViewController.view.transform = .identity
}, completion: nil)
}
}
}

还有呈现动画 Controller :

import UIKit

final class PresentingAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

guard let presentedViewController = transitionContext.viewController(forKey: .to) else {
return
}

let springTiming = UISpringTimingParameters(dampingRatio: 1.0, initialVelocity: CGVector(dx:1.0, dy: 1.0))
let animator: UIViewPropertyAnimator = UIViewPropertyAnimator(duration: transitionDuration(using: transitionContext), timingParameters: springTiming)

let containerView = transitionContext.containerView
containerView.addSubview(presentedViewController.view)

let finalFrameForPresentedView = transitionContext.finalFrame(for: presentedViewController)
presentedViewController.view.frame = finalFrameForPresentedView

// Move it below the screen so it slides up
presentedViewController.view.frame.origin.y = containerView.bounds.height

animator.addAnimations {
presentedViewController.view.frame = finalFrameForPresentedView
}

animator.addCompletion { (animationPosition) in
if animationPosition == .end {
transitionContext.completeTransition(true)
}
}

animator.startAnimation()
}

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.6
}
}

以及解散动画 Controller :

import UIKit

final class DismissingAnimationController: NSObject, UIViewControllerAnimatedTransitioning {

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

guard let presentedViewController = transitionContext.viewController(forKey: .from) else {
return
}

guard let presentingViewController = transitionContext.viewController(forKey: .to) else {
return
}

let finalFrameForPresentedView = transitionContext.finalFrame(for: presentedViewController)

let containerView = transitionContext.containerView
let offscreenFrame = CGRect(x: finalFrameForPresentedView.minX, y: containerView.bounds.height, width: finalFrameForPresentedView.width, height: finalFrameForPresentedView.height)

let springTiming = UISpringTimingParameters(dampingRatio: 1.0, initialVelocity: CGVector(dx:1.0, dy: 1.0))
let animator: UIViewPropertyAnimator = UIViewPropertyAnimator(duration: transitionDuration(using: transitionContext), timingParameters: springTiming)

animator.addAnimations {
presentedViewController.view.frame = offscreenFrame
}

animator.addCompletion { (position) in
if position == .end {
// Complete transition
transitionContext.completeTransition(true)
}
}

animator.startAnimation()
}

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.6
}
}

最佳答案

好吧,我明白了。 iOS 13 似乎没有使用缩放变换。正如所解释的那样,在您这样做的那一刻,旋转设备将修改呈现 View 的框架,并且由于您已经将 transform 应用于 View , View 将以意想不到的方式调整大小并且转换将不再有效。

解决方案是改为使用 z 轴透视图,这会给你完全相同的结果,但这样做会在旋转等情况下幸存下来,因为你所做的只是将 View 移回 3D 空间(Z 轴) ,从而有效地缩小它。这是为我完成此操作的转换 (Swift):

  func calculatePerspectiveTransform() -> CATransform3D {
let eyePosition:Float = 10.0;
var contentTransform:CATransform3D = CATransform3DIdentity
contentTransform.m34 = CGFloat(-1/eyePosition)
contentTransform = CATransform3DTranslate(contentTransform, 0, 0, -2)
return contentTransform
}

这是一篇解释其工作原理的文章:https://whackylabs.com/uikit/2014/10/29/add-some-perspective-to-your-uiviews/

在您的 UIPresenterController 中,您还需要执行以下操作才能正确处理这种跨旋转的转换:

  override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)

// Reset transform before we rotate and then apply it again during rotation
if let presentingView = presentingViewController.view {
presentingView.layer.transform = CATransform3DIdentity
}

coordinator.animate(alongsideTransition: { [weak self] (context) in
if let presentingView = self?.presentingViewController.view {
presentingView.layer.transform = self?.calculatePerspectiveTransform() ?? CATransform3DIdentity
}
})
}

关于iOS 13 风格的 UIPresentationController 不依赖快照?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57048831/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com