私は新しい iOS 7 カスタム トランジション API に手を出して、見つけたすべてのチュートリアル/ドキュメントを調べましたが、特定のシナリオでこのようなものを理解できないようです。
したがって、本質的に私が実装しようとしているのは、上にスワイプして VC に移行するビューの UIPanGestureRecognizer です。VC のビューは下から上にスライドし、現在のビューは指を上にドラッグすると上にスライドします。
インタラクション トランジションなしでこれを達成するのに問題はありませんが、インタラクション (パン ジェスチャ) を実装すると、トランジションを完了できないようです。
アニメーターコントローラーを販売するために必要な UIViewControllerTransitionDelegate に準拠する VC からの関連コードを次に示します。
- (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
繰り返しになりますが、ここでコードを実行し、遷移を意図的にキャンセルするために完全にスワイプしないと、フラッシュが表示され、スワイプ先のビュー コントローラーが表示されます。これは、移行が完了したかキャンセルされたかに関係なく発生します。
ただし、ボタンを使用して閉じると、アニメーター ビュー コントローラーで指定されたトランジションが取得されます。