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 中的事件监听器相当于啥?

IOS/Objective-C:改变图像视图的色调

IOS / Objective-C:检查互联网连接的最快方法 - 2017 [重复]

IOS / Objective-C:以编程方式在按钮下的中心线

iOS Objective-C dealloc方法释放的是啥?

IOS/objective-c/core-data:如何从相关实体获取属性