Segue animation similar to opening an app in iOS 7

2019-04-17 02:45发布

I am willing to create a segue animation similar to opening an app in iOS 7. Now I consider this approach: Non-segue implementation, but encountered an issue: if being implemented in custom segue, the code cannot resize viewcontroller's frame, which is principal part of the animation. As I can see, it applies viewcontroller's position, but cannot change it's size. Am I correct, that property viewcontroller.view.frame cannot be animated and has to remain constant and equal to size of the device's screen? I already implemented something similar with CGAffineTransformMakeScale, but its a bit weird, so, I am looking for better solution. Below I paste the code I use for the segue.

#import "ZoomSegue.h"
#import "MiniMapViewController.h"
#import "InteractiveMapViewController.h"

@implementation ZoomSegue

- (void)perform {
    InteractiveMapViewController *sourceViewController = self.sourceViewController;
    MiniMapViewController *destinationViewController = self.destinationViewController;

    destinationViewController.view.alpha = 0.0f;
    destinationViewController.view.hidden = NO;


    //Just to check, lets make view really small. Position it to the center we get from the segue.
    destinationViewController.view.frame = CGRectMake(_originatingPoint.x, _originatingPoint.y, 60.0f, 60.0f);

    [sourceViewController.view addSubview:destinationViewController.view];


    float animationDuration = 1.5f;

    [UIView animateWithDuration:animationDuration/2.0f animations:^{
        destinationViewController.view.alpha = 1.0f;
    }];



    [UIView animateWithDuration:animationDuration animations:^{


        //Just to check, lets make view very big. It does not work, although, the view goes to the upper left corner, so position works, but not the size
        CGRect x  = CGRectMake(0.0f, 0.0f, 9590.0f, 91366.0f);

        destinationViewController.view.frame = x;
    }];
}
@end

2条回答
男人必须洒脱
2楼-- · 2019-04-17 03:10

I've translated the same code in SWIFT.

class CustomOpenSegue: UIStoryboardSegue {
   var iconFrame = CGRect()

   override func perform(){

    var sourceViewController: UIViewController = self.sourceViewController as UIViewController
    var bg:UIView = sourceViewController.view.snapshotViewAfterScreenUpdates(true)
    bg.frame = UIScreen.mainScreen().bounds
    var destinationViewController: UIViewController = self.destinationViewController as UIViewController
    var icon:UIView = destinationViewController.view.snapshotViewAfterScreenUpdates(true)
    icon.frame = self.iconFrame
    icon.alpha = 0.0

    sourceViewController.view.addSubview(icon)



    UIView.animateWithDuration(0.25, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
        icon.alpha = 1.0
    }, completion: nil )

    UIView.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
            () -> Void in
            icon.frame = UIScreen.mainScreen().bounds
            bg.frame = self.zoomedRect

    }) { (finished) -> Void in

        sourceViewController.navigationController?.pushViewController(destinationViewController, animated: false)
        icon.removeFromSuperview()
        bg.removeFromSuperview()


        }
    }


    var zoomedRect:CGRect{
        var screenWidth = UIScreen.mainScreen().bounds.size.width
        var screenHeight = UIScreen.mainScreen().bounds.size.height

        var size = screenWidth / self.iconFrame.size.width
        var x = screenWidth / 2 - CGRectGetMidX(self.iconFrame) * size
        var y = screenHeight / 2 - CGRectGetMidY(self.iconFrame) * size

        return CGRectMake(x, y, screenWidth * size, screenHeight * size)
    }
}

And this is how you call it:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if segue is CustomOpenSegue{
    let customOpenSegue = segue as CustomOpenSegue
    customOpenSegue.iconFrame = self.mapButtonFrame!
    }
}
查看更多
神经病院院长
3楼-- · 2019-04-17 03:25

I don't know if you're correct, but a better way to do it anyway is to use a snapshot view. This code puts a small snapshot in the center of the screen then expands it to full size,

- (void)perform {
    UIView *sourceView = ((UIViewController *)self.sourceViewController).view;
    UIView *destinationView = [((UIViewController *)self.destinationViewController).view snapshotViewAfterScreenUpdates:YES];
    destinationView.frame = CGRectMake(0, 0, 5, 5);
    destinationView.center = CGPointMake(sourceView.center.x, sourceView.center.y);
    [sourceView addSubview:destinationView];

    [UIView animateWithDuration:1
                     animations:^{
                         destinationView.frame = sourceView.frame;
                     }
                     completion:^(BOOL finished) {
                         [[self sourceViewController] presentViewController:[self destinationViewController] animated:NO completion:nil];
                     }];

}

After Edit:

Here is a translation of the code in the link you provided that converts that animation into a segue,

-(void)perform {
    CGFloat duration = .25;
    UIViewController *source = self.sourceViewController;
    UIView *bg = [source.view snapshotViewAfterScreenUpdates:YES];
    bg.frame = UIScreen.mainScreen.bounds;
    UIViewController *dest = self.destinationViewController;
    UIView *icon = [dest.view snapshotViewAfterScreenUpdates:YES];
    icon.frame = self.iconFrame;
    icon.alpha = 0.0f;
    [source.view addSubview:bg];
    [source.view addSubview:icon];
    [UIView animateWithDuration:duration animations:^{
        icon.alpha = 1.0f;
    }];
    [UIView animateWithDuration:duration*2 animations:^{ 
        icon.frame = UIScreen.mainScreen.bounds;
        bg.frame = [self zoomedRect];
    } completion:^(BOOL finished) {
        [source presentViewController:dest animated:NO completion:nil];
        [bg removeFromSuperview];
        [icon removeFromSuperview];
    }];

}



- (CGRect)zoomedRect {
    float screenWidth = UIScreen.mainScreen.bounds.size.width;
    float screenHeight = UIScreen.mainScreen.bounds.size.height;

    float size = screenWidth / self.iconFrame.size.width;
    float x = screenWidth/2 - (CGRectGetMidX(self.iconFrame) * size);
    float y = screenHeight/2 - (CGRectGetMidY(self.iconFrame) * size);

    return CGRectMake(x, y, screenWidth * size, screenHeight * size);
}

I have a CGRect property, iconFrame in the .h file of the segue. I performed the segue from a tap gesture recognizer that was attached to the icon that will be expanded. You need to pass the frame of that icon to the segue, which I do in the source view controller's prepareForSegue method,

-(void)prepareForSegue:(SpringboardSegue *)segue sender:(UITapGestureRecognizer *)sender {
    segue.iconFrame = sender.view.frame;
}
查看更多
登录 后发表回答