Ios UINavigationController在高度更改时是否会切断内容?(gif)
我把一个UINavigationController放进了一个可扩展的“抽屉”。 我的目标是让导航堆栈中的每个viewController都有自己的“首选”高度 假设VC1需要很高。当从VC2导航回VC1时,我希望它将其高度设置为“高”。动画逻辑似乎正在运行,即使使用了滑动的交互 但由于某些原因,navigationController中的ViewController被“切断”。它们的约束是正确的,但没有更新(?)。或者,在我再次触摸视图之前,部分内容根本不会呈现。底部的不可见区域甚至可以接受触摸 看一看: 预期结果是ContentViewController(第一个和第二个)始终延伸到屏幕底部。它们必须这样做,所以问题是它们在转换期间不会“渲染”(?) 在UINavigationController的委托中,我执行以下操作:Ios UINavigationController在高度更改时是否会切断内容?(gif),ios,swift,uiviewcontroller,uinavigationcontroller,ios-animations,Ios,Swift,Uiviewcontroller,Uinavigationcontroller,Ios Animations,我把一个UINavigationController放进了一个可扩展的“抽屉”。 我的目标是让导航堆栈中的每个viewController都有自己的“首选”高度 假设VC1需要很高。当从VC2导航回VC1时,我希望它将其高度设置为“高”。动画逻辑似乎正在运行,即使使用了滑动的交互 但由于某些原因,navigationController中的ViewController被“切断”。它们的约束是正确的,但没有更新(?)。或者,在我再次触摸视图之前,部分内容根本不会呈现。底部的不可见区域甚至可以接受触
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
transitionCoordinator?.animate(alongsideTransition: { (context) in
drawer.heightConstraint.constant = targetHeight
drawer.superview?.layoutIfNeeded()
}, completion: { (context) in
print("done")
})
}
高度的变化是完美的。但导航中的内容将不符合要求。navigationController被约束为前导、尾随、底部和存储的高度约束,该约束会更改其常量
只要我触摸/拖动navigationController/内容,它就会立即“渲染未渲染的内容”,一切正常。为什么会这样
检查视图层次结构时,如下所示:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if let superHeight = view.superview?.superview?.bounds.size.height, let drawer = (view.superview as? Drawer), let targetHeight = (viewController as? Contained)?.currentNotch.height(availableHeight: superHeight){
transitionCoordinator?.animate(alongsideTransition: { (context) in
drawer.heightConstraint.constant = targetHeight
drawer.superview?.layoutIfNeeded()
self.updateHeights(to: targetHeight, willShow: viewController) // <- Here
}, completion: { (context) in
self.updateHeights(to: targetHeight, willShow: viewController) // <- Here
})
}
}
NavigationController的高度与需要的一样高,但内容的高度与转换开始时整个抽屉的高度相同,并且在我触摸它之前不会更新。
为什么?
编辑:如果你想看的话,我已经把代码推到了。不过要小心,还有其他几个问题(动画等),不要介意。我只想知道为什么导航不会显示“未来”高度。您可以通过为导航控制器设置自定义animationController,并在自定义UIViewControllerAnimatedTransition实现的animateTransition功能中为destinationView设置适当的帧来解决上述问题。结果将类似于下面的gif图像中的结果 您的自定义UIViewControlleranimated转换可能如下所示
final class TransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let presenting: Bool
init(presenting: Bool) {
self.presenting = presenting
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return TimeInterval(UINavigationController.hideShowBarDuration)
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromView = transitionContext.view(forKey: .from) else { return }
guard let toView = transitionContext.view(forKey: .to) else { return }
let duration = transitionDuration(using: transitionContext)
let container = transitionContext.containerView
if presenting {
container.addSubview(toView)
} else {
container.insertSubview(toView, belowSubview: fromView)
}
let toViewFrame = toView.frame
toView.frame = CGRect(x: presenting ? toView.frame.width : -toView.frame.width, y: toView.frame.origin.y, width: toView.frame.width, height: toView.frame.height)
UIView.animate(withDuration: duration, animations: {
toView.frame = toViewFrame
fromView.frame = CGRect(x: self.presenting ? -fromView.frame.width : fromView.frame.width, y: fromView.frame.origin.y, width: fromView.frame.width, height: fromView.frame.height)
}) { (finished) in
container.addSubview(toView)
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
}
}
并且,在导航控制器中提供自定义animationController,如下所示
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
switch operation {
case .push:
return TransitionAnimator(presenting: true)
case .pop:
return TransitionAnimator(presenting: false)
default:
return nil
}
}
PS:-我还在您的github回购中提出了拉取请求。您可以自己更新控制器高度: 首先,您需要保留对控制器的引用:
class ContainedNavigationController: UINavigationController, Contained, UINavigationControllerDelegate {
private var controllers = [UIViewController]()
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { controllers = viewControllers }
/* Rest of the class */
然后可以相应地更新它们的高度不要忘记添加新控制器
private func updateHeights(to height: CGFloat, willShow controller: UIViewController) {
controller.view.frame.size.height = height
_ = controllers.map { $0.view.frame.size.height = height }
}
您可以在代码中使用它,如下所示:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if let superHeight = view.superview?.superview?.bounds.size.height, let drawer = (view.superview as? Drawer), let targetHeight = (viewController as? Contained)?.currentNotch.height(availableHeight: superHeight){
transitionCoordinator?.animate(alongsideTransition: { (context) in
drawer.heightConstraint.constant = targetHeight
drawer.superview?.layoutIfNeeded()
self.updateHeights(to: targetHeight, willShow: viewController) // <- Here
}, completion: { (context) in
self.updateHeights(to: targetHeight, willShow: viewController) // <- Here
})
}
}
我已经添加了一个来自的拉取请求。您可以像下面这样设置大小: 参考-> 您的导航vc:
class ContainedNavigationController:UINavigationController, Contained, UINavigationControllerDelegate{
///Your code
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
viewController.updateViewConstraints()
// Your code start
// end
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
viewController.updateViewConstraints()
}
}
您可以设置高度约束并调用layoutIfNeeded方法,而无需过渡块 下面是相同的代码段:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if let superHeight = view.superview?.superview?.bounds.size.height, let drawer = (view.superview as? Drawer), let targetHeight = (viewController as? Contained)?.currentNotch.height(availableHeight: superHeight){
drawer.heightConstraint.constant = targetHeight
drawer.layoutIfNeeded()
}
}
@sti请让我知道如果有帮助,请投相同的票您是否在github中托管了此示例?如果是这样,您可以共享链接吗?如果您将包含viewController的泛型与子viewController一起使用,您将对正在发生的事情有更多的控制和可见性。@Subramanianamariappan将链接添加到github。@DavidH它是一个
UIView
包含UIAvigationController
的UIViewController。使用navigationController的原因是为了获得免费的导航动画和逻辑。你是说我应该在某个地方插入UIViewController“我的堆栈”吗?这不就是我的基本UIView吗,因为我只是添加子视图(vc.view)
?还是说我应该删除navigationController并创建自己的导航?如果您想查看,请添加到github的链接。@AlessandroOrnano我现在快速修复了分支并“还原”了主节点。Subramanians解决方案确实解决了请求的问题,但代价是在navigationController中丢失了大量本机转换。你可以试试别的,我不着急。这太棒了!我可能会接受这个答案(无论如何要到明天才能颁发赏金)。但是-我注意到这个解决方案意味着失去一些不错的本机转换特性。首先,启动刷卡(在真实设备上)比较困难。也许是因为本地的刷卡而崩溃了?此外,刷卡的金额并不随手指移动,它显示了某种“easeInOut”——我无法识别的行为。但最值得注意的是,导航栏不再转换。“后退”按钮/后退标题/标题不跟随滑动。我必须手动复制这些,还是可以继承一些?通过自定义添加到视图中的平移手势识别器,可以轻松地进行滑动。已经给出了一个带更改的拉取请求。在您上次的PR中,开始刷卡更容易,但现在无法拖动以扩展整个抽屉,这是此元素的一个关键功能。也许有一种方法可以让一些“同时”的逻辑发挥作用。我来玩玩。但这仍然不是一个完全完美的答案,因为我仍然失去了导航栏的转换,但我也会尝试一下。你的回答解决了主要问题,但也产生了一些其他问题。这是一个很好的答案,如果在接下来的6天内没有其他人解决它而没有副作用,我将接受它。(我将您的拉取请求移动到它自己的分支并重置主控,以便其他人可以尝试,如果他们愿意)太棒了!我一直认为,由于UIWindow中有关UIViewController的神秘规则,它无法显式设置控制器内在视图的框架。但有几个问题:1。为什么手动保留对控制器的引用?既然这是一个UINavigationController
,我们就不能使用self.viewControllers来执行此操作吗?事实上,为什么要为所有视图控制器应用高度,而不仅仅是原始视图
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if let superHeight = view.superview?.superview?.bounds.size.height, let drawer = (view.superview as? Drawer), let targetHeight = (viewController as? Contained)?.currentNotch.height(availableHeight: superHeight){
drawer.heightConstraint.constant = targetHeight
drawer.layoutIfNeeded()
}
}