简体   繁体   English

IOS / Objective-C:在没有情节提要Segue的情况下,可以在模式转换中使用自定义Segue吗?

[英]IOS/Objective-C: Possible to Use Custom Segue in Modal Transition in Absence of a Storyboard Segue?

I have two View Controllers in Storyboard and I would like to present the second one from the first modally using a custom downward segue (the opposite of the regular cover vertical). 我在情节提要中有两个View Controller,我想使用自定义的向下顺序(与常规封面垂直线相反)以模态形式显示第一个视图控制器。

I have subclassed storyboard segue with code that I hope will work. 我用希望能起作用的代码将情节提要segue子类化。

However, in this instance, I did not drag a segue in Storyboard from one view controller to the other. 但是,在这种情况下,我没有将Storyboard中的segue从一个视图控制器拖到另一个视图控制器。 Instead, I handle the Modal Presentation in code. 相反,我用代码处理模式表示。

Is it possible to invoke a custom segue if you are calling the second view controller in code? 如果要在代码中调用第二个视图控制器,是否可以调用自定义序列? Or do you have to have an actual segue in storyboard to which you assign the custom class? 还是您必须在情节提要中为您分配自定义类的实际脚本?

If possible in code, where would you put the code? 如果可能的话,将代码放在哪里?

Here is code I am using to present the modal View Controller 这是我用来展示模式视图控制器的代码

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"chat" bundle:nil];
    UIViewController *myVC = [storyboard instantiateViewControllerWithIdentifier:@"chatVC"];
    [(UINavigationController*)self.window.rootViewController presentViewController:myVC animated:NO completion:nil];

It seems like you're trying to accomplish many custom animation transitions within your application, so I'd recommend you roll with your own animator classes instead of trying to create custom segues. 似乎您正在尝试在应用程序中完成许多自定义动画过渡,所以我建议您使用自己的动画师类来滚动,而不要尝试创建自定义序列。 Similar to the example I posted to you previous question (linked in my comment above), you're going to want to setup some sort of delegate (in the previous example it was a UINavigationControllerDelegate) to handle determining which custom animator classes to use for presenting/dismissing (in the previous example it was for pushing/popping) certain view controllers: 类似于我向您上一个问题发布的示例(在上面的评论中链接),您将需要设置某种委托(在上一个示例中是UINavigationControllerDelegate)来处理确定要用于哪个自定义动画类显示/关闭某些视图控制器(在上一个示例中是用于推送/弹出):

Here's an example of what I mean: 这是我的意思的示例:

ViewController.m (using this as the UIViewControllerTransitioningDelegate): 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): 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: 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

My guess is that you're going to want a custom slide up animation upon dismissal as well, so you'll want one more animator which implements that custom transition: 我的猜测是,您还需要在解雇时自定义向上滑动的动画,因此您将需要一个实现该自定义过渡的动画制作器:

SlideUpAnimator.h: 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: 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

The complete animation will end up looking like this: 完整的动画最终看起来像这样:

Custom_Downward_Animation_Transition Custom_Downward_Animation_Transition

Here's some links that should be helpful: 以下是一些有用的链接:

https://developer.apple.com/library/archive/featuredarticles/ViewControllerPGforiPhoneOS/CustomizingtheTransitionAnimations.html 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/uiviewcontrollertransitioningdelegate?language=objc

https://developer.apple.com/documentation/uikit/uiviewcontrolleranimatedtransitioning?language=objc https://developer.apple.com/documentation/uikit/uiviewcontrolleranimatedtransitioning?language=objc

Edit: 编辑:

As far as your other question as to where to put this in your own code: This is highly dependent on your application structure, so without seeing more context of the classes you're attempting to use them on, it's hard to say the best approach. 关于将其放在您自己的代码中的位置的其他问题:这高度依赖于您的应用程序结构,因此,在未看到尝试使用它们的类的更多上下文的情况下,很难说出最佳方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM