自定义Modal转场动画

想要制作如下效果:

点击小图,从小图的位置生成一张一样大小和位置的图片,然后放大到全屏,在点击全屏图片,图片缩小回到小图的位置

首先定义两个Delegate,分别管理新控制器弹出(Present)和收起(Dissmis)的一些参数

PicBrowserPresentedAnimationDelegate.h

#import <Foundation/Foundation.h>

@protocol PicBrowserPresentedAnimationDelegate <NSObject>

- (CGRect) startRect;
- (CGRect) endRect;
- (UIImageView*) imageView;

@end

PicBrowserDismissedAnimationDelegate.h

#import <Foundation/Foundation.h>

@protocol PicBrowserDismissedAnimationDelegate <NSObject>

- (UIImageView*)imageView;

@end

然后创建一个转场动画的动画管理类,并且实现协议: UIViewControllerTransitioningDelegate和UIViewControllerAnimatedTransitioning

PicBrowserAnimation.h

#import <Foundation/Foundation.h>
#import "PicBrowserDismissedAnimationDelegate.h"
#import "PicBrowserPresentedAnimationDelegate.h"

@interface PicBrowserAnimation : NSObject <UIViewControllerTransitioningDelegate,UIViewControllerAnimatedTransitioning>

@property (assign, nonatomic)BOOL isPresented;
@property (weak, nonatomic)id<PicBrowserDismissedAnimationDelegate> dismissDelegate;
@property (weak, nonatomic)id<PicBrowserPresentedAnimationDelegate> presentDelegate;

@end

PicBrowserAnimation.m

#import "PicBrowserAnimation.h"
#import "PicBrowserDismissedAnimationDelegate.h"
#import "PicBrowserPresentedAnimationDelegate.h"

@interface PicBrowserAnimation()

@end

@implementation PicBrowserAnimation

#pragma mark UIViewControllerTransitioningDelegate

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    self.isPresented = YES;
    return self;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    self.isPresented = NO;
    return self;
}

#pragma mark UIViewControllerAnimatedTransitioning
- (void)animateTransition:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
    if(self.isPresented) {
        [self animateForPresentedView:transitionContext];
    } else {
        [self animateForDismissedView:transitionContext];
    }
}

- (NSTimeInterval)transitionDuration:(nullable id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.3;
}

- (void)animateForPresentedView:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
    if(self.presentDelegate) {
        //取出要弹出的View
        UIView *presentedView = [transitionContext viewForKey:UITransitionContextToViewKey];
        //将presentedView添加到containerView中
        [transitionContext.containerView addSubview:presentedView];
        CGRect startRect = [self.presentDelegate startRect];
        UIImageView *imageView = [self.presentDelegate imageView];
        [transitionContext.containerView addSubview:imageView];
        imageView.frame = startRect;

        //执行动画
        [presentedView setAlpha:0.0];
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            imageView.frame = [self.presentDelegate endRect];
            [transitionContext.containerView setBackgroundColor:[UIColor blackColor]];
        } completion:^(BOOL finished) {
            //通知上下文已经完成动画
            [presentedView setAlpha:1.0];
            [transitionContext completeTransition:YES];
            [imageView removeFromSuperview];
            [transitionContext.containerView setBackgroundColor:[UIColor clearColor]];
        }];
    }
}

- (void)animateForDismissedView:(nonnull id<UIViewControllerContextTransitioning>)transitionContext {
    if(self.dismissDelegate) {
        UIView *dissmisView = [transitionContext viewForKey:UITransitionContextFromViewKey];
        [dissmisView removeFromSuperview];

        UIImageView *imageView = [self.dismissDelegate imageView];
        [transitionContext.containerView addSubview:imageView];

        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            imageView.frame = [self.presentDelegate startRect];
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:YES];
        }];
    }
}

@end

在需要转场的控制器中的转场方法,找到需要转场的实际View作为Delegate实现动画方法

@property (strong, nonatomic)PicBrowserAnimation *picBrowserAnimation;

- (PicBrowserAnimation *)picBrowserAnimation {
    if(!_picBrowserAnimation) {
        _picBrowserAnimation = [[PicBrowserAnimation alloc]init];
    }
    return _picBrowserAnimation;
}

- (void)imageSelected:(NSNotification*) notification {
    AVIMImageMessage *message = (AVIMImageMessage*)notification.userInfo[@"message"];
    ImageBrowserController *imageBrowserController = [ImageBrowserController imageBrowserController:message];
    ChatImageView *imageView = (ChatImageView*)notification.object;
    imageBrowserController.modalPresentationStyle = UIModalPresentationCustom;
    imageBrowserController.transitioningDelegate = self.picBrowserAnimation;

    self.picBrowserAnimation.presentDelegate = imageView;
    self.picBrowserAnimation.dismissDelegate = imageBrowserController;

    [self presentViewController:imageBrowserController animated:YES completion:nil];
}

Present:

ChatImageView.m,动画开始的小图,以及起始Frame和结束Frame

@implementation ChatImageView

- (CGRect)endRect {
    CGSize imageSize = CGSizeMake([[self.message.file.metaData objectForKey:@"width"] floatValue],[[self.message.file.metaData objectForKey:@"height"] floatValue]);
    CGFloat imageW = [UIScreen mainScreen].bounds.size.width;
    CGFloat imageH = imageW / imageSize.width * imageSize.height;
    return CGRectMake(0, ([UIScreen mainScreen].bounds.size.height - imageH) * 0.5, imageW, imageH);
}

- (UIImageView *)imageView {
    UIImage *image = [[SDWebImageManager sharedManager].imageCache imageFromMemoryCacheForKey:self.message.file.url];
    UIImageView *imageView = [[UIImageView alloc]init];
    imageView.image = image;
    return imageView;
}

- (CGRect)startRect {
    return [self convertRect:self.frame toView:[UIApplication sharedApplication].keyWindow];
}

@end

Dismiss

#pragma mark PicBrowserDismissedAnimationDelegate
- (UIImageView *)imageView {
    UIImageView *imageView = [[UIImageView alloc]init];
    [imageView sd_setImageWithURL:[NSURL URLWithString:self.message.file.url]];
    CGSize imageSize = CGSizeMake([[self.message.file.metaData objectForKey:@"width"] floatValue],[[self.message.file.metaData objectForKey:@"height"] floatValue]);
    CGFloat imageW = [UIScreen mainScreen].bounds.size.width;
    CGFloat imageH = imageW / imageSize.width * imageSize.height;
    imageView.frame = CGRectMake(0, ([UIScreen mainScreen].bounds.size.height - imageH) * 0.5, imageW, imageH);
    return imageView;
}

results matching ""

    No results matching ""