Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/97.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios UINavigationController在高度更改时是否会切断内容?(gif)_Ios_Swift_Uiviewcontroller_Uinavigationcontroller_Ios Animations - Fatal编程技术网

Ios UINavigationController在高度更改时是否会切断内容?(gif)

Ios UINavigationController在高度更改时是否会切断内容?(gif),ios,swift,uiviewcontroller,uinavigationcontroller,ios-animations,Ios,Swift,Uiviewcontroller,Uinavigationcontroller,Ios Animations,我把一个UINavigationController放进了一个可扩展的“抽屉”。 我的目标是让导航堆栈中的每个viewController都有自己的“首选”高度 假设VC1需要很高。当从VC2导航回VC1时,我希望它将其高度设置为“高”。动画逻辑似乎正在运行,即使使用了滑动的交互 但由于某些原因,navigationController中的ViewController被“切断”。它们的约束是正确的,但没有更新(?)。或者,在我再次触摸视图之前,部分内容根本不会呈现。底部的不可见区域甚至可以接受触

我把一个UINavigationController放进了一个可扩展的“抽屉”。 我的目标是让导航堆栈中的每个viewController都有自己的“首选”高度

假设VC1需要很高。当从VC2导航回VC1时,我希望它将其高度设置为“高”。动画逻辑似乎正在运行,即使使用了滑动的交互

但由于某些原因,navigationController中的ViewController被“切断”。它们的约束是正确的,但没有更新(?)。或者,在我再次触摸视图之前,部分内容根本不会呈现。底部的不可见区域甚至可以接受触摸

看一看:

预期结果是ContentViewController(第一个和第二个)始终延伸到屏幕底部。它们必须这样做,所以问题是它们在转换期间不会“渲染”(?)

在UINavigationController的委托中,我执行以下操作:

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()
    }
}