具有单独移动背景的自定义 segue

Posted

技术标签:

【中文标题】具有单独移动背景的自定义 segue【英文标题】:Custom segue with separate moving background 【发布时间】:2015-01-08 19:51:29 【问题描述】:

我想实现这个动画中的效果

我的应用程序中应该有两个(或更多)ViewControllers 具有自定义 segue。过渡应该只是将新的ViewController 向上移动。并且在背景中应该有一个图像,它会随着每个 segue 移动一点。

我总共考虑了 3 个ViewControllers。一种用于背景,处理背景移动并以模态方式显示ViewController12。但我不知道如何实现这一目标。有没有人有更好的方法或其他想法?

编辑 如果动画没有开始,请在另一个选项卡中打开 .gif 以查看它。

【问题讨论】:

【参考方案1】:

免责声明:这只是您可以做的一些想法。您的情况听起来非常具体,自定义 segue 可能会很快变得非常复杂。因此,此代码可能无法完全满足您的需要。这让我深入了解了我过去是如何解决类似问题的。


我不完全确定你的问题,但我可以告诉你我过去做了什么。

首先,我创建了一个继承自 UIStoryboardSegue 的自定义 segue 类。我假设您知道如何设置故事板以使用 segue(即连接按钮事件或类似事件)。我为此开设的课程是我的自定义 segue 课程。

在这个类的perform 方法中,我利用UIStoryboardSegue 的sourceViewControllerdestinationViewController 属性来访问视图。我将目标视图控制器的视图添加到源视图控制器的视图层次结构中。这样我就可以制作动画了。

对于您的情况,您可以创建一个 @protocol 来访问您的背景属性,如下所示:

ViewControllerWithBackground.h

@protocol ViewControllerWithBackground

@property (nonatomic) IBOutlet UIImageView *backgroundImage;

@end

将该协议分配给每个将使用 segue 的视图控制器。在 segue 代码中,您可以在类的 perform 方法中向上/向下移动背景以执行 segue,如下所示:

自定义 UIStoryboardSegue 方法

- (void)perform 
    UIViewController *sourceViewController = self.sourceViewController;
    UIViewController *destinationViewController = self.destinationViewController;

    if ([self.sourceViewController conformsToProtocol:@protocol(ViewControllerWithBackground)] &&
            [self.destinationViewController conformsToProtocol:@protocol(ViewControllerWithBackground)]) 

        UIViewController<ViewControllerWithBackground> *sourceViewController = (UIViewController<ViewControllerWithBackground> *)self.sourceViewController;
        UIViewController<ViewControllerWithBackground> *destinationViewController = (UIViewController<ViewControllerWithBackground> *)self.destinationViewController;

        // Remove the existing view from the frame so we can animate it separately
        UIView *sourceView = sourceViewController.view;

        // Place a container view onto the frame that will contain the destination view and the current view
        sourceViewController.view = [[UIView alloc] initWithFrame:sourceView.frame];

        // Add the destination view controller's view and the place the source view on top of it so it's hidden
        [sourceViewController.view addSubview:destinationViewController.view];
        [sourceViewController.view addSubview:sourceView];

        // Set the final destination for the background image (i.e. where do you want it to end up in the destination view)
        CGRect currentBackgroundFrame = sourceViewController.backgroundImage.frame;
        CGRect finalBackgroundPosition = CGRectMake(0, 0, currentBackgroundFrame.size.width, currentBackgroundFrame.size.height); // ADD X,Y VALUES TO ANIMATE IT TO HERE

        // We are setting the background image's frame for the destination view controller here. (Remember: it's hidden the source view controller's view right now)
        destinationViewController.backgroundImage.frame = finalBackgroundPosition;

        // Animate everything
        [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut animations:^
            // We are animating the original view's background image only
            sourceViewController.backgroundImage.frame = finalBackgroundPosition;

            // OTHER ANIMATION VALUES HERE

         completion:^(BOOL finished) 
            // We have to dispatch because there will be unbalanced calls for begin/end transition because this transition hasn't finished executing
            dispatch_async(dispatch_get_main_queue(), ^(void)
                [sourceViewController presentViewController:destinationViewController animated:NO completion:^
                    // Reset the view hierarchy to the original for unwinding (optional)
                    sourceViewController.view = sourceView;
                ];
            );

        ];

    

可选

如果您需要代码来判断背景图像应该向上还是向下移动,请不要忘记您已经对 segue 进行了子类化,以便可以将该信息从视图控制器的 prepareForSegue:sender: 方法传递到您的自定义 segue perform 方法如下:

源视图控制器示例

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 

    // Code that tells me this event requires the background to animate like it's moving up instead of down

    if ([segue isKindClass:[CustomStoryBoardBackgroundThingSegue class]]) 
        CustomStoryBoardBackgroundThingSegue *customSegue = (CustomStoryBoardBackgroundThingSegue *)segue;
        segue.animateUp = YES;
    

【讨论】:

感谢您的详细解答。我想我会用你的建议做到这一点。但是一个问题。为什么要将destinationViewController.view 添加到sourceViewController.view?我不能单独使用两者。你知道,我不明白这样做的意义 :D 仍然非常感谢你。这对我帮助很大! 我用它来动画和淡出源视图控制器。因为目标视图控制器在 presentViewController... 方法之前不在堆栈上,它会淡出到白屏。目标视图被放置在后面,以便在目标视图控制器位于视图堆栈中之前使其淡入。 嗯好的,现在我明白了。再次感谢!! 你知道如何用swift写这行吗? UIViewController&lt;ViewControllerWithBackground&gt; *sourceViewController = (UIViewController&lt;ViewControllerWithBackground&gt; *)self.sourceViewController;

以上是关于具有单独移动背景的自定义 segue的主要内容,如果未能解决你的问题,请参考以下文章

没有segue的自定义关闭过渡

在 UITableView 中嵌入的自定义 UICollectionView 中执行 Segue

IOS / Objective-C / Storyboard:从左到右的自定义Segue在视图控制器之间创建黑条

具有错误背景颜色的自定义 UITableViewCell

具有背景和项目的自定义 UIActivityViewController

Swift 中的自定义 Segue