【发布时间】:2014-06-06 15:46:22
【问题描述】:
总结
我有一个内容 UIViewController,它使用自定义转换呈现设置 UIViewController。演示文稿是presentViewController:animated:completion:。
当我稍后使用dismissViewControllerAnimated:completion: 取消设置时,呈现控制器突然跳回到设置控制器呈现之前的初始位置。
我在设备上解决了这个问题,但在模拟器上没有。但是,我想知道我做错了什么,而不是闯入一个让它消失的困境。我还计划让这个动画具有交互性,我怀疑这个问题会在我这样做时放大。
自定义过渡 - 打开引擎盖
想要的效果是 presenting 控制器在屏幕上向下滑动,而 presenting 控制器看起来躺在它的后面,从它抬起来填满屏幕.呈现控制器的顶部在呈现控制器的使用期间保持在屏幕上。它停留在屏幕底部,但在呈现的控制器之上。
您可以想象抬起汽车上的发动机罩(前部呈现控制器)以查看后面的发动机(显示的设置),但发动机罩在一些上下文中保持在底部可见。
我计划对此进行改进,以使呈现控制器看起来确实以 3D 方式以透视方式抬起,但我还没有做到这一点。
当关闭设置时,原始呈现控制器(引擎盖)应向上滑回屏幕,呈现的控制器(设置)略微后退(关闭引擎盖)。
代码
这是在屏幕上和屏幕外切换设置的方法(它只是由 UIButton 调用)。您会注意到呈现视图控制器将自己设置为<UIViewControllerTransitioningDelegate>。
-(void) toggleSettingsViewController
{
const BOOL settingsAreShowing = [self presentedViewController] != nil;
if(!settingsAreShowing)
{
UIViewController *const settingsController = [[self storyboard] instantiateViewControllerWithIdentifier: @"STSettingsViewController"];
[settingsController setTransitioningDelegate: self];
[settingsController setModalPresentationStyle: UIModalPresentationCustom];
[self presentViewController: settingsController animated: YES completion: nil];
}
else
{
[self dismissViewControllerAnimated: YES completion: nil];
}
}
要实现<UIViewControllerAnimatedTransitioning>,呈现视图控制器也只是将自身返回为<UIViewControllerAnimatedTransitioning>
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source
{
return self;
}
-(id<UIViewControllerAnimatedTransitioning>) animationControllerForDismissedController:(UIViewController *)dismissed
{
// Test Point 1.
return self;
}
所以最后,呈现视图控制器将收到animateTransition::
-(void) animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIViewController *const fromController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *const toController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
const BOOL isUnwinding = [toController presentedViewController] == fromController;
const BOOL isPresenting = !isUnwinding;
UIViewController * presentingController = isPresenting ? fromController : toController;
UIViewController * presentedController = isPresenting ? toController : fromController;
if(isPresenting)
{
// Add the presented controller (settings) to the view hierarchy _behind_ the presenting controller.
[[transitionContext containerView] insertSubview: [presentedController view] belowSubview: [presentingController view]];
// Set up the initial position of the presented settings controller. Scale it down so it seems in the distance. Alpha it down so it is dark and shadowed.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.7;
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Lift up the presented controller.
presentedController.view.transform = CGAffineTransformMakeScale(1.0, 1.0);
// Brighten the presented controller (out of shadow).
presentedController.view.alpha = 1;
// Push the presenting controller down the screen – 3d effect to be added later.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
} completion: ^(BOOL finished){
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
else
{
// Test Point 2.
// !!!This line should not be needed!!!
// It resets the presenting controller to where it ought to be anyway.
presentingController.view.layer.transform = CATransform3DMakeTranslation(0,400,0);
[UIView animateWithDuration: [self transitionDuration: transitionContext] animations:^{
// Bring the presenting controller back to its original position.
presentingController.view.layer.transform = CATransform3DIdentity;
// Lower the presented controller again and put it back in to shade.
presentedController.view.transform = CGAffineTransformMakeScale(0.9, 0.9);
presentedController.view.alpha = 0.4;
} completion:^(BOOL finished) {
[transitionContext completeTransition: ![transitionContext transitionWasCancelled]];
}];
}
}
-(NSTimeInterval) transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
{
return 0.5;
}
问题
在上面的代码中,我已经指出 !!!这行不应该是必需的!!!。
发生的情况是,在 Test Point 1 和 Test Point 2 之间,呈现视图控制器的屏幕位置被重置为默认的全屏边界。因此,它并没有在屏幕底部准备好再次平滑动画,而是突然向上跳到屏幕的位置,它也应该平滑动画!
我尝试了各种方法来为屏幕下方的呈现视图控制器设置动画:
- 我更改了它的视图框架。
- 我已更改其视图的变换。
- 我已更改其视图层的 3d 变换。
在所有情况下,在 测试点 1,当请求转换委托时,呈现控制器已按我的预期设置。但是,在所有情况下,在 测试点 2,呈现的视图控制器都丢失了正确的位置,并且已被“清除”为具有我想要为其设置动画的正常全屏位置。 p>
在上面的工作中,我明确地将呈现视图控制器重新定位到它应该在动画开始时的位置 !!!不应该需要这条线!!!。这似乎在使用当前版本的 iOS 7 的设备上工作。但是,在模拟器上,控制器在清除的位置至少可见一帧。
我怀疑我做错了什么,而且我会在解决另一个问题时遇到麻烦。
有什么想法吗?谢谢!
【问题讨论】:
标签: ios uiviewcontroller uikit uiviewanimationtransition