如何完成交互式 UIViewController 过渡?
Posted
技术标签:
【中文标题】如何完成交互式 UIViewController 过渡?【英文标题】:How to complete interactive UIViewController transition? 【发布时间】:2013-10-01 03:38:11 【问题描述】:我一直在尝试使用新的 ios 7 自定义转换 API,并查看了我能找到的所有教程/文档,但我似乎无法为我的特定场景弄清楚这些东西。
所以基本上我要实现的是一个视图上的 UIPanGestureRecognizer,我将向上滑动并转换到一个 VC,该 VC 的视图将从底部向上滑动,而当我将手指向上拖动时,当前视图会向上滑动。
没有交互转换我没有问题,但是一旦我实现了交互(平移手势),我似乎无法完成转换。
下面是来自 VC 的符合 UIViewControllerTransitionDelegate 的相关代码,这是出售动画控制器所需的:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
if ([segue.identifier isEqualToString:@"Swipe"])
NSLog(@"PREPARE FOR SEGUE METHOD CALLED");
UIViewController *toVC = segue.destinationViewController;
[interactionController wireToViewController:toVC];
toVC.transitioningDelegate = self;
toVC.modalPresentationStyle = UIModalPresentationCustom;
#pragma mark UIViewControllerTransition Delegate Methods
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController: (UIViewController *)presented presentingController: (UIViewController *)presenting sourceController:(UIViewController *)source
NSLog(@"PRESENTING ANIMATION CONTROLLER CALLED");
SwipeDownPresentationAnimationController *transitionController = [SwipeDownPresentationAnimationController new];
return transitionController;
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
NSLog(@"DISMISS ANIMATION CONTROLLER CALLED");
DismissAnimatorViewController *transitionController = [DismissAnimatorViewController new];
return transitionController;
- (id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator
NSLog(@"Interaction controller for dimiss method caled");
return interactionController.interactionInProgress ? interactionController:nil;
注意:交互滑动仅用于关闭 VC,这就是它在interactionControllerForDismissal 方法中的原因
这是解除动画的代码,当我点击按钮解除它时,它可以正常工作:
#import "DismissAnimatorViewController.h"
@implementation DismissAnimatorViewController
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
return 1.0;
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
NSTimeInterval duration = [self transitionDuration:transitionContext];
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
CGRect initialFrameFromVC = [transitionContext initialFrameForViewController:fromVC];
UIView *containerView = [transitionContext containerView];
CGRect screenBounds = [[UIScreen mainScreen] bounds];
NSLog(@"The screen bounds is :%@", NSStringFromCGRect(screenBounds));
toVC.view.frame = CGRectOffset(initialFrameFromVC, 0, screenBounds.size.height);
toVC.view.alpha = 0.2;
CGRect pushedPresentingFrame = CGRectOffset(initialFrameFromVC, 0, -screenBounds.size.height);
[containerView addSubview:toVC.view];
[UIView animateWithDuration:duration
delay:0
usingSpringWithDamping:0.6
initialSpringVelocity:0
options:UIViewAnimationOptionCurveEaseIn
animations:^
fromVC.view.frame = pushedPresentingFrame;
fromVC.view.alpha = 0.2;
toVC.view.frame = initialFrameFromVC;
toVC.view.alpha = 1.0;
completion:^(BOOL finished)
[transitionContext completeTransition:YES];
];
@end
这是用作交互控制器的 UIPercentDrivenInteractiveTransition 子类的代码:
#import "SwipeInteractionController.h"
@implementation SwipeInteractionController
BOOL _shouldCompleteTransition;
UIViewController *_viewController;
- (void)wireToViewController:(UIViewController *)viewController
_viewController = viewController;
[self prepareGestureRecognizerInView:_viewController.view];
- (void)prepareGestureRecognizerInView:(UIView*)view
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
gesture.minimumNumberOfTouches = 1.0;
[view addGestureRecognizer:gesture];
- (CGFloat)completionSpeed
return 1 - self.percentComplete;
NSLog(@"PERCENT COMPLETE:%f",self.percentComplete);
- (void)handleGesture:(UIPanGestureRecognizer*)gestureRecognizer
// CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];
CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view.superview];
switch (gestureRecognizer.state)
case UIGestureRecognizerStateBegan:
// 1. Start an interactive transition!
self.interactionInProgress = YES;
[_viewController dismissViewControllerAnimated:YES completion:nil];
break;
case UIGestureRecognizerStateChanged:
// 2. compute the current position
CGFloat fraction = fabsf(translation.y / 568);
NSLog(@"Fraction is %f",fraction);
fraction = fminf(fraction, 1.0);
fraction = fmaxf(fraction, 0.0);
// 3. should we complete?
_shouldCompleteTransition = (fraction > 0.23);
// 4. update the animation controller
[self updateInteractiveTransition:fraction];
NSLog(@"Percent complete:%f",self.percentComplete);
break;
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled:
// 5. finish or cancel
NSLog(@"UI GESTURE RECOGNIZER STATE CANCELED");
self.interactionInProgress = NO;
if (!_shouldCompleteTransition || gestureRecognizer.state == UIGestureRecognizerStateCancelled)
[self cancelInteractiveTransition];
NSLog(@"Interactive Transition is cancled.");
else
NSLog(@"Interactive Transition is FINISHED");
[self finishInteractiveTransition];
break;
default:
NSLog(@"Default is being called");
break;
@end
再一次,当我现在运行代码并且我没有一直滑动以有目的地取消转换时,我只是得到了一个闪光,并出现了我想要滑动到的视图控制器。无论转换是完成还是取消,都会发生这种情况。
但是,当我通过按钮关闭时,我得到了动画视图控制器中指定的过渡。
【问题讨论】:
确保覆盖UIPercentDrivenInteractiveTransition
开始、结束和更新动画的方法。我没有看到它们在您的代码中的任何地方实现。
好的,试试看,谢谢。
@AshFurrow:我确实阅读了您关于自定义转换的 Teehan+Lax 教程,其中您提到了覆盖 UIPercentDrivenInteractiveTransition
方法,但我不明白它的原因。有必要吗?我目前正处于没有它的实现中间,并且诚然我遇到了一些奇怪的行为(例如,完成动画从手势结束的百分比再次重复在初始完成后,屏幕变黑交互式取消),但我不能 100% 确定这是原因。 Anyhoo,只是想知道您是否有理由进行覆盖。谢谢!
重写UIPercentDrivenInteractiveTransition
不是绝对必要的,但它是最简单且“Apple 友好”的方法。
遇到同样的问题。完成块永远不会被调用,转换完成也不会被取消。 IOS8。找到方法了吗,怎么解决?
【参考方案1】:
我可以在这里看到几个问题 - 虽然我不能确定这些是否会解决您的问题!
首先,您的动画控制器的 UIView 动画完成块具有以下内容:
[transitionContext completeTransition:YES];
而它应该根据交互控制器的结果返回完成,如下所示:
[transitionContext completeTransition:![transitionContext transitionWasCancelled]]
另外,我发现如果您告诉UIPercentDrivenInteractiveTransition
转换已 100% 完成,它不会调用动画控制器完成块。作为一种解决方法,我将其限制在 ~99.9%
https://github.com/ColinEberhardt/VCTransitionsLibrary/issues/4
我在这里创建了许多示例交互和动画控制器,您可能会发现它们很有用:
https://github.com/ColinEberhardt/VCTransitionsLibrary
【讨论】:
感谢科林的帮助。我试过你说的,但还是有问题。嗯..【参考方案2】:我遇到了同样的问题。我尝试了上述修复和其他修复,但没有任何效果。然后我偶然发现了https://github.com/MrAlek/AWPercentDrivenInteractiveTransition,它修复了所有问题。
将其添加到项目后,只需将 UIPercentDrivenInteractiveTransition
替换为 AWPercentDrivenInteractiveTransition
。
此外,您必须在开始交互式过渡之前设置动画师。就我而言,我对UIViewControllerAnimatedTransitioning
和UIViewControllerInteractiveTransitioning
使用相同的类,所以我只是在init()
中使用了它:
init()
super.init()
self.animator = self
【讨论】:
以上是关于如何完成交互式 UIViewController 过渡?的主要内容,如果未能解决你的问题,请参考以下文章
允许在下面呈现的 UIViewController 上的 UIViewController 上进行交互
如何使用完成按钮呈现包含 iOS App Store 的 UIViewController
UIViewController 交互式过渡 - 取消交互式关闭时呈现的视图消失