gpt4 book ai didi

ios - UINavigationController忘记了自定义过渡动画后如何旋转子 Controller

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

我一直在努力解决以下问题。我在文档中找不到我做错的任何事情。我已经通过调试器进行了爬网,并将各种信息都转储到了控制台,但是无法解决所看到的问题。

我的顶级视图控制器是UINavigationController的子类。它包含UIPageViewController的子类,该子类将用于可视化我的数据。它还包含用于设置应用程序设置的UITableViewController的子类。该“选项”视图通过推送功能“链接”到页面视图控制器。至此,一切正常。

当我想区分可视化数据的各种方式(页面视图控制器中的水平滚动)与引入选项视图之间的视觉过渡时,问题就开始了。因此,我创建了一个自定义动画,以将选项控制器从屏幕顶部“拉入”(按入),或者将选项控制器“滚动”到屏幕顶部(弹出)。我使用navigationController:animationControllerFor:operation:from:to:方法在导航控制器上设置此动画。

在显示选项控制器之前,在设备旋转期间一切似乎都工作正常。显示/关闭选项控制器后,数据可视化控制器的布局在旋转过程中会分解。当关闭选项控制器时,它以设备所处的方向正确显示,但以相反的方向错误地播放。

似乎导航控制器(或可能的页面视图控制器)已经忘记了如何处理状态,导航和工具栏的高度。



以下显示的调试屏幕截图说明了5s模拟器上的问题


初始状态。请注意,内容视图(红色)在状态,导航和工具栏下方。


enter image description here


将方向旋转到水平。到目前为止,一切正常。调试控制台显示将视图“旋转”为(568x212)的大小,状态,导航和工具栏的前后高度,屏幕大小,框架矩形和图层位置。我没有在此处显示它,但是图层锚点从(0.5,0.5)不变。


请注意,目标旋转大小是使用以下规则设置的:


rot_width(568)= old_frame_height(460)+ sum_of_bar_heights(108)
rot_height(212)= old_frame_width(320)-sum_of_bar_heights(108)


并使用以下规则设置结果帧大小:


new_frame_width(568)= rot_width(568)
new_frame_height(256)= rot_height(212)+ change_in_bar_height(108-64)


所得到的帧原点(0,64)从屏幕顶部偏移状态栏(20)和导航栏(44)的总和。

enter image description here


将方向旋转回垂直方向。再次,一切都很好。调试控制台为“反向”旋转添加与上述相同的信息。旋转大小和生成的帧大小遵循与上述相同的规则。


enter image description here


使用自定义动画将选项编辑器控制器视图推入导航堆栈。调试控制台为上面的(当前不可见)内容视图添加与上面相同的信息。请注意,没有任何改变。


enter image description here


使用自定义动画将选项编辑器控制器视图弹出导航堆栈。上方的内容视图返回视图。调试控制台添加与上述相同的信息。同样,没有任何变化。


注意,堆叠顺序与显示选项编辑器之前的顺序不同。

使用默认的过渡动画器时,此堆栈重排序不成立(通过从pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted返回nil)

enter image description here


重复第1步。这就是要“变态”的地方。内容视图不再紧贴导航栏和工具栏。调试控制台显示,轮换的所有内容与步骤1中的相同。


但是,轮换的结果与步骤1不同。规则似乎已更改。不再调整生成的框架大小以适应状态,导航和工具栏高度的更改,并且框架原点与旋转之前的原始位置相同。

enter image description here


重复执行步骤2。看来,所有内容都是固定的,但这仅仅是因为它正在按照新的调整大小规则播放。


enter image description here



在此处显示了我的动画师类(完整显示,除了用于产生上面显示的调试信息的探针外):

class OptionsViewAnimator: NSObject, UIViewControllerAnimatedTransitioning
{
var type : UINavigationControllerOperation

init(_ type : UINavigationControllerOperation)
{
self.type = type
}

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

func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
{
if self.type == .push { showOptions(using:transitionContext) }
else if self.type == .pop { hideOptions(using:transitionContext) }
}

func showOptions(using context: UIViewControllerContextTransitioning)
{
let src = context.viewController(forKey: .from)!
let srcView = context.view(forKey: .from)!
let dstView = context.view(forKey: .to)!
var dstEnd = context.finalFrame(for: context.viewController(forKey: .to)!)

let barHeight = (src.navigationController?.toolbar.frame.height) ?? 0.0

dstEnd.size.height += barHeight

dstView.frame = dstEnd
dstView.layer.position = dstEnd.origin
dstView.layer.anchorPoint = CGPoint(x:0.0,y:0.0)
dstView.transform = dstView.transform.scaledBy(x: 1.0, y: 0.01)

UIApplication.shared.keyWindow!.insertSubview(dstView, aboveSubview: srcView)

UIView.animate(withDuration: 0.35, animations:
{
dstView.transform = .identity
}
) {
(finished)->Void in
context.completeTransition( !context.transitionWasCancelled )
}
}

func hideOptions(using context: UIViewControllerContextTransitioning)
{
let dst = context.viewController(forKey: .to)!
let srcView = context.view(forKey: .from)!
let dstView = context.view(forKey: .to)!
let dstEnd = context.finalFrame(for: context.viewController(forKey: .to)!)

dstView.frame = dstEnd

srcView.layer.position = dstEnd.origin
srcView.layer.anchorPoint = CGPoint(x:0.0,y:0.0)
srcView.transform = .identity

UIApplication.shared.keyWindow!.insertSubview(dstView, belowSubview: srcView)

UIView.animate(withDuration: 0.35, animations:
{
srcView.transform = srcView.transform.scaledBy(x: 1.0, y: 0.01)
}
) {
(finished)->Void in
context.completeTransition( !context.transitionWasCancelled )
}
}
}


感谢您提供的所有/所有帮助。
麦克风

最佳答案

由于您希望它覆盖UINavigation控制器栏,因此有任何理由不使用自定义模式(在情节提要中以模态形式呈现)。无论哪种方式,我都构建了它以使其与添加窗口无关。在您测试之后,请让我知道,但在我的测试中,两者都可以正常使用。

 import UIKit

class OptionsViewAnimator: NSObject, UIViewControllerAnimatedTransitioning,UIViewControllerTransitioningDelegate
{
var isPresenting = true
fileprivate var isNavPushPop = false

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

func animateTransition(using transitionContext: UIViewControllerContextTransitioning)
{
if isPresenting { showOptions(using:transitionContext) }
else { hideOptions(using:transitionContext) }
}

func showOptions(using context: UIViewControllerContextTransitioning)
{
let src = context.viewController(forKey: .from)!
let dstView = context.view(forKey: .to)!
let frame = context.finalFrame(for: context.viewController(forKey: .to)!)
let container = context.containerView
dstView.frame = frame
dstView.layer.position = CGPoint(x: container.frame.origin.x, y: container.frame.origin.y + frame.origin.y)
print("container = \(container.frame)")
dstView.layer.anchorPoint = CGPoint(x:container.frame.origin.x,y:container.frame.origin.y)
dstView.transform = dstView.transform.scaledBy(x: 1.0, y: 0.01)
container.addSubview(dstView)

UIView.animate(withDuration: 0.35, animations: { dstView.transform = .identity } )
{
(finished)->Void in
src.view.transform = .identity
context.completeTransition( !context.transitionWasCancelled )
}
}

func hideOptions(using context: UIViewControllerContextTransitioning)
{
let srcView = context.view(forKey: .from)!
let dstView = context.view(forKey: .to)!

let container = context.containerView
container.insertSubview(dstView, belowSubview: srcView)
srcView.layer.anchorPoint = CGPoint(x:container.frame.origin.x,y:container.frame.origin.y)
dstView.frame = context.finalFrame(for: context.viewController(forKey: .to)!)
dstView.layoutIfNeeded()
UIView.animate(withDuration: 0.35, animations:
{ srcView.transform = srcView.transform.scaledBy(x: 1.0, y: 0.01) } )
{
(finished)->Void in

context.completeTransition( !context.transitionWasCancelled )
}
}

func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
{
isPresenting = false
return self
}


func animationController(forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController) -> UIViewControllerAnimatedTransitioning?
{
isPresenting = true
return self
}
}

extension OptionsViewAnimator: UINavigationControllerDelegate
{
func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationControllerOperation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?
{
isNavPushPop = true
self.isPresenting = operation == .push
return self
}
}


//要用作模式而不是导航,请在下面执行
在视图控制器中声明为属性

    let animator = OptionsViewAnimator()


并准备进行搜索看起来像

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let dvc = segue.destination
dvc.transitioningDelegate = animator
}


否则推和弹出

self.navigationController?.delegate = animator


或设置为nil

此外,对于导航控制器类中的项目,它应如下所示。

func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationControllerOperation,
from fromVC: UIViewController,
to toVC: UIViewController
) -> UIViewControllerAnimatedTransitioning?
{
var animator : OptionsViewAnimator?

if ( toVC is OptionsViewController && operation == .push ){
animator = OptionsViewAnimator()
animator?.isPresenting = true
}else if ( fromVC is OptionsViewController && operation == .pop ){
animator = OptionsViewAnimator()
animator?.isPresenting = false
}
return animator
}

关于ios - UINavigationController忘记了自定义过渡动画后如何旋转子 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42479321/

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