横向自定义UIViewController动画的解决方法?

Jas*_*ore 18 uiviewcontroller modalviewcontroller ios7

我有一个自定义动画UIViewController转换,似乎iOS中存在一个错误,它以横向方向搞砸了布局.在主要的动画方法中,我给出了混合的横向和纵向视图.(在肖像中,视图都是人像,所以没问题.)

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
{
  UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
  UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  UIView *containerView = [transitionContext containerView];

  // fromViewController.view => landscape, transform
  // toViewController.view => portrait, transform
  // containerView => portrait, no transform

  [containerView addSubview:toViewController.view];

  // ...animation... //
}
Run Code Online (Sandbox Code Playgroud)

我知道frame当视图有变换时属性不可靠 - 所以我猜这是问题的根源.在横向模式下,to/from viewControllers视图具有90度顺时针变换[0 -1 1 0].我已经尝试使用边界/中心来调整视图的大小和位置,以及删除变换然后重新应用它,但是UIKit与我打架并且坚持将视图显示为肖像.烦!

在屏幕截图中,深灰色是UIWindow背景,红色是添加的模态视图控制器,应覆盖整个屏幕.

红色视图是纵向的

有人找到了解决方法吗?

Jas*_*ore 17

好的,修复非常简单:

将视图添加到容器之前,将toViewController框架设置为容器.

toViewController.view.frame = containerView.frame;
[containerView addSubview:toViewController.view];
Run Code Online (Sandbox Code Playgroud)

更新:您仍然存在一个限制,即您不知道框架的方向.它最初是肖像,但在屏幕上显示时会延伸到横向.如果您想要从右侧滑动视图,在横向中它可能会从"顶部"滑入(如果查看其他横向,则滑入底部!)


Dan*_*sko 13

我遇到了这个问题,我只是觉得上述解决方案没有做到这一点.我提出了一个不需要hacky代码和硬编码帧的解决方案.

UIView有一个很棒的功能,可以将CGRect转换为另一个(即; +[UIView convertRect:fromView:])的坐标空间.因此,我希望详细介绍一种可以在任何方向上实现此效果的简单方法,而无需任何硬编码值.在这个例子中,我们想要一个简单的动画,从屏幕右侧滑动视图.

所以在我们的动画师中animateTransition(:)我们可以简单地执行以下操作:

迅速

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
    let toViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
    let fromViewController = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!

    let toView = toViewController.view
    let fromView = fromViewController.view
    let containerView = transitionContext.containerView()

    if(isPresenting) {
        //now we want to slide in from the right
        let startingRect = CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0)
        toView.frame = containerView.convertRect(startingRect, fromView:fromView);
        containerView.addSubview(toView)
        let destinationRect = containerView.convertRect(fromView.bounds, fromView: fromView)
        UIView.animateWithDuration(transitionDuration(transitionContext),
            delay: 0,
            usingSpringWithDamping: 0.7,
            initialSpringVelocity: 0.7,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                toView.frame = destinationRect
        }, completion: { (complete) -> Void in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        })
    } else {
        //we want to slide out to the right
        let endingRect = containerView.convertRect(CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0), fromView: fromView)
        UIView.animateWithDuration(transitionDuration(transitionContext),
            delay: 0,
            usingSpringWithDamping: 0.7,
            initialSpringVelocity: 0.7,
            options: .BeginFromCurrentState,
            animations: { () -> Void in
                fromView.frame = endingRect
            }, completion: { (complete) -> Void in
                if !transitionContext.transitionWasCancelled() {
                    fromView.removeFromSuperview()
                }
                transitionContext.completeTransition(!transitionContext.transitionWasCancelled())
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

Objective-C的

UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

UIView *toView = toViewController.view;
UIView *fromView = fromViewController.view;
UIView *containerView = [transitionContext containerView];

if(self.isPresenting) {
    //now we want to slide in from the right
    CGRect startingRect = CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0);
    toView.frame = [containerView convertRect:startingRect fromView:fromView];
    [containerView addSubview:toView];
    [UIView animateWithDuration:[self transitionDuration:transitionContext]
                     animations:^{
                         toView.frame = [containerView convertRect:fromView.bounds
                                                          fromView:fromView];
                     }
                     completion:^(BOOL finished) {
                         [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                     }];

} else {
    //we want to slide out to the right
    [UIView animateWithDuration:[self transitionDuration:transitionContext]
                     animations:^{
                         CGRect endingRect = CGRectOffset(fromView.bounds, CGRectGetWidth(fromView.bounds), 0);
                         fromView.frame = [containerView convertRect:endingRect fromView:fromView];
                     }
                     completion:^(BOOL finished) {
                         [fromView removeFromSuperview];
                         [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
                     }];

}
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助那些在同一条船上来到这里的人(如果确实如此,那么投票不会受到伤害:))


Alf*_*sen 8

现有的答案是部分方式,但不是所有方式(我们希望在两个设备上都有适当的帧和旋转处理,所有方向,用于动画和交互式转换).

这篇博文有助于:

http://www.brightec.co.uk/blog/ios-7-custom-view-controller-transitions-and-rotation-making-it-all-work

它引用了Apple支持人员陈述问题的真实性质:

"对于自定义表示过渡,我们在窗口和windows rootViewController视图之间设置了一个中间视图.这个视图是你在其中执行动画的容器视图.由于iOS上自动旋转的实现细节,当界面旋转时,我们应用一个仿射变换到windows rootViewController的视图并相应地修改它的边界.因为containerView从窗口而不是根视图控制器的视图继承它的尺寸,所以它总是处于纵向方向.

"如果您的演示动画取决于呈现视图控制器的方向,则需要检测呈现视图控制器的方向并适当地修改动画.系统会将正确的变换应用于传入的视图控制器,但您需要动画师需要配置传入视图控制器的帧."

但它没有解决交互式过渡问题.

我在这里找到了一个完整的问题解决方案:

https://github.com/alfiehanssen/Cards

实质上,您需要根据viewControllers之一(toViewController或fromViewController)的方向计算viewControllers的帧,而不是transitionContext的containerView的边界.