IOS/Objective-C:在没有 Storyboard Segue 的情况下可以在模态转换中使用自定义 Segue?
Posted
技术标签:
【中文标题】IOS/Objective-C:在没有 Storyboard Segue 的情况下可以在模态转换中使用自定义 Segue?【英文标题】:IOS/Objective-C: Possible to Use Custom Segue in Modal Transition in Absence of a Storyboard Segue? 【发布时间】:2018-09-18 21:37:30 【问题描述】:我在 Storyboard 中有两个视图控制器,我想使用自定义向下转场(与常规封面垂直相反)以模态方式展示第一个视图控制器中的第二个。
我用希望能工作的代码对故事板进行了子类化。
但是,在这种情况下,我没有将 Storyboard 中的 segue 从一个视图控制器拖到另一个视图控制器。相反,我在代码中处理模态表示。
如果您在代码中调用第二个视图控制器,是否可以调用自定义 segue?或者您是否必须在情节提要中有一个实际的 segue 来分配自定义类?
如果可能在代码中,您会将代码放在哪里?
这是我用来呈现模态视图控制器的代码
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"chat" bundle:nil];
UIViewController *myVC = [storyboard instantiateViewControllerWithIdentifier:@"chatVC"];
[(UINavigationController*)self.window.rootViewController presentViewController:myVC animated:NO completion:nil];
【问题讨论】:
只需要写一个自定义的过渡动画。与故事板或转场无关。 “如果可能在代码中,你会把代码放在哪里?”任何你喜欢的地方。这节课。呈现的视图控制器的类。一个助手类。随便。 可下载示例(Swift 和不同的动画,但思路完全相同)github.com/mattneub/Programming-ios-Book-Examples/blob/master/… 查看我对您上一个问题的回复:***.com/a/52284947/7833793,它展示了如何创建自定义过渡动画 对不起,我想我的意思是你会在哪里指定类或调用代码?我写了一个 UIStoryboardsegue 子类。使用故事板版本,我只是在身份检查器中更改了类的名称。但是,如果没有拖拽的 segue,我不确定在哪里告诉程序有关课程的信息。除非你的意思是我不应该继承 uistoryboardsegue 而是应该创建一个自定义动画? 【参考方案1】:您似乎正在尝试在应用程序中完成许多自定义动画转换,因此我建议您使用自己的动画师类而不是尝试创建自定义转场。与我发布给您上一个问题的示例类似(链接在我上面的评论中),您将需要设置某种委托(在上一个示例中它是 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(自定义向下动画):
#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
编辑:
至于您关于将其放在您自己的代码中的哪个位置的其他问题:这高度依赖于您的应用程序结构,因此如果没有看到您尝试使用它们的类的更多上下文,很难说最好的方法。
【讨论】:
以上是关于IOS/Objective-C:在没有 Storyboard Segue 的情况下可以在模态转换中使用自定义 Segue?的主要内容,如果未能解决你的问题,请参考以下文章
IOS / Objective-C:检查互联网连接的最快方法 - 2017 [重复]
IOS / Objective-C:以编程方式在按钮下的中心线