Кажется, что вы пытаетесь выполнить множество пользовательских переходов анимации в своем приложении, поэтому я рекомендую вам использовать собственные классы аниматоров, а не пытаться создавать собственные переходы.Как и в примере, который я опубликовал на предыдущем вопросе (ссылка которого приведена в моем комментарии выше), вы захотите настроить своего рода делегат (в предыдущем примере это был UINavigationControllerDelegate) для обработки определения, какие пользовательские классы аниматоров использовать дляпредставление / отклонение (в предыдущем примере это было для нажатия / выталкивания) определенных контроллеров представления:
Вот пример того, что я имею в виду:
ViewController.m (используя это как UIViewControllerTransitioningDelegate):
#import "ViewController.h"
#import "SlideDownAnimator.h"
#import "SlideUpAnimator.h"
@interface ViewController () <UIViewControllerTransitioningDelegate>
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)_presentCustomDownward:(id)sender {
// setup a fake view controller we're going to present
UIViewController *fakeSecondViewController = [[UIViewController alloc] init];
fakeSecondViewController.view.backgroundColor = [UIColor blueColor];
// make sure to set the desination view controller's transition delegate
// this doesn't have to be set to self here, you can set it anything that will implement: UIViewControllerTransitioningDelegate
fakeSecondViewController.transitioningDelegate = self;
// when we call present on the view controller it asks the transitioningDelegate for an animation coordinator which we're going to provide below
[self.navigationController presentViewController:fakeSecondViewController animated:YES completion:^{
// dismis after a couple seconds to show what the custom dismiss looks like (obviously this is just for the example code, you will handle your own dismissal)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
});
}];
}
// delegate call for presentation
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source {
// return our own custom Animator class (which adheres to UIViewControllerAnimatedTransitioning protocol)
return [[SlideDownAnimator alloc] init];
}
// delegate call for dismissal
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
// return our own custom Animator class (which adheres to UIViewControllerAnimatedTransitioning protocol)
return [[SlideUpAnimator alloc] init];
}
SlideDownAnimator.h (Custom Down Animator):
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SlideDownAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end
NS_ASSUME_NONNULL_END
SlideDownAnimator.m:
#import "SlideDownAnimator.h"
@implementation SlideDownAnimator
- (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)transitionContext {
return 0.4f;
}
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
// grab the toViewController (the vc being presented)
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// manually add it to our container view
[[transitionContext containerView] addSubview:toViewController.view];
// get the frame so we can do some of our own animations on it
CGRect toVCFrame = toViewController.view.frame;
CGFloat toVCHeight = toVCFrame.size.height;
// offset the y coordiante by it's height so that it's completely above our current screen
toVCFrame.origin.y = -toVCHeight;
// set the initial frame so it's above our screen
[toViewController.view setFrame:toVCFrame];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
// animate the y position to 0 so it slides down
CGRect finalVCFrame = toViewController.view.frame;
finalVCFrame.origin.y = 0;
[toViewController.view setFrame:finalVCFrame];
} completion:^(BOOL finished) {
// make sure to call this so we'll call back to our presentViewdController's completion block
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
@end
Я предполагаю, что вы захотитенастраиваемая анимация перемещения вверх при увольнении, поэтому вам понадобится еще один аниматор, который реализует этот пользовательский переход:
SlideUpAnimator.h:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SlideUpAnimator : NSObject <UIViewControllerAnimatedTransitioning>
@end
NS_ASSUME_NONNULL_END
SlideUpAnimator.m:
#import "SlideUpAnimator.h"
@implementation SlideUpAnimator
- (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)transitionContext {
return 0.4f;
}
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
// grab our fromViewController (the vc being dismissed)
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
// and our toViewController (the vc that will be shown after dismissal)
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
// add our toViewController as a subview of our container view (make sure to add it beneath the dismissing view controller so we can let it complete it's animation first)
[[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
[UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
// push the view back up above the screen
CGRect fromVCFrame = fromViewController.view.frame;
fromVCFrame.origin.y = -fromVCFrame.size.height;
[fromViewController.view setFrame:fromVCFrame];
} completion:^(BOOL finished) {
// make sure to call this so we'll call back to our presentViewdController's completion block
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
}];
}
@end
Полная анимация будет выглядеть следующим образом:
Custom_Downward_Animation_Transition
Вот несколько полезных ссылок:
https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html
https://developer.apple.com/documentation/uikit/uiviewcontrollertransitioningdelegate?language=objc
https://developer.apple.com/documentation/uikit/uiviewcontrolleranimatedtransitioning?language=objc
Редактировать:
Что касается вашего второго вопроса относительно того, где поместить это в ваш собственный код: это сильно зависит от структуры вашего приложения, поэтому, не видя больше контекста классов, на которых вы пытаетесь их использовать,Трудно сказать лучший подход.