利用转场动画来实现类似QQ语音通话界面隐藏和出现的效果

浮动可拖拽按钮功能的实现可以参考前一篇文章。利用手势拖拽控件并设置拖拽范围.
接下来利用转场动画来实现类似QQ语音通话界面隐藏和出现的转场动画效果。
第一步,建立一个继承于NSObject的类,实现UIViewControllerAnimatedTransitioning协议,然后利用贝塞尔曲线来绘制界面出现和消失的动画路径。代码如下:

#import 
#import 

typedef NS_ENUM(NSUInteger ,ZTransitionType)
{
    ZTransitionTypeShow = 0,
    ZTransitionTypeDismiss
};
@interface ZTransition : NSObject

/*
 *转场动画操作type
 */
@property (assign,nonatomic)ZTransitionType transitionType;


+ (instancetype)transitionWithType:(ZTransitionType)transitionType;

- (instancetype)initWithTransitionType:(ZTransitionType)transitionType;

@end

#import "ZTransition.h"
#import "ViewController.h"

#define Animaton_Time 0.5f
@implementation ZTransition

+ (instancetype)transitionWithType:(ZTransitionType)transitionType
{
    return [[self alloc]initWithTransitionType:transitionType];
}

- (instancetype)initWithTransitionType:(ZTransitionType)transitionType
{
    self = [super init];
    if (self)
    {
        self.transitionType = transitionType;
    }
    return self;
}


#pragma mark 转场动画时长
- (NSTimeInterval)transitionDuration:(id)transitionContext
{
    return Animaton_Time;
}

- (void)animateTransition:(id)transitionContext
{
    switch (self.transitionType)
    {
        case ZTransitionTypeShow:
        {
            [self showAnimaton:transitionContext];
        }
            break;
        case ZTransitionTypeDismiss:
        {
            [self dismissAnimation:transitionContext];
        }
            break;
        default:
            break;
    }
}

#pragma mark -- show
- (void)showAnimaton:(id)transitionContext
{
    UIViewController * toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UINavigationController * fromVC = (UINavigationController *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    ViewController * temVC = fromVC.viewControllers.lastObject;
    UIView * containerView = [transitionContext containerView];
    [containerView addSubview:toVC.view];

    //TODO:画两个圆
    UIBezierPath *startRound = [UIBezierPath bezierPathWithOvalInRect:temVC.roundFrame];
    CGFloat x = MAX(temVC.roundFrame.origin.x, containerView.frame.size.width - temVC.roundFrame.origin.x);
    CGFloat y = MAX(temVC.roundFrame.origin.y, containerView.frame.size.height - temVC.roundFrame.origin.y);
    CGFloat radius = sqrtf(pow(x, 2) + pow(y, 2));
    UIBezierPath *endRound = [UIBezierPath bezierPathWithArcCenter:containerView.center
                                                            radius:radius
                                                        startAngle:0
                                                          endAngle:M_PI * 2
                                                         clockwise:YES];
    //TODO:创建CAShpeLayer遮罩层
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.path = endRound.CGPath;
    toVC.view.layer.mask = maskLayer;

    //TODO:动画路径
    CABasicAnimation *maskLayerAni = [CABasicAnimation animationWithKeyPath:@"path"];
    maskLayerAni.delegate = self;
    maskLayerAni.fromValue = (__bridge id _Nullable)(startRound.CGPath);
    maskLayerAni.toValue = (__bridge id _Nullable)(endRound.CGPath);
    maskLayerAni.duration = [self transitionDuration:transitionContext];
    maskLayerAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [maskLayerAni setValue:transitionContext forKey:@"transitionContext"];
    [maskLayer addAnimation:maskLayerAni forKey:@"path"];

}

#pragma mark ---dismiss
- (void)dismissAnimation:(id)transitionContext
{
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UINavigationController *toVC = (UINavigationController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    ViewController *tempVC = toVC.viewControllers.lastObject;
    UIView *containerView = [transitionContext containerView];

    //TODO:画两个圆
    CGFloat radius = sqrtf(containerView.frame.size.height * containerView.frame.size.height + containerView.frame.size.width * containerView.frame.size.width)/2;
    UIBezierPath *startRoundPath = [UIBezierPath bezierPathWithArcCenter:containerView.center
                                                                  radius:radius
                                                              startAngle:0
                                                                endAngle:M_PI * 2
                                                               clockwise:YES];
    UIBezierPath *endRoundPath = [UIBezierPath bezierPathWithOvalInRect:tempVC.roundFrame];

    //TODO:创建遮罩层
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.fillColor = [UIColor colorWithRed:32/255 green:62/255 blue:85/255 alpha:1.0].CGColor;
    maskLayer.path = endRoundPath.CGPath;
    fromVC.view.layer.mask = maskLayer;

    //TODO:创建转场动画路径
    CABasicAnimation *maskAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    maskAnimation.delegate = self;
    maskAnimation.fromValue = (__bridge id _Nullable)(startRoundPath.CGPath);
    maskAnimation.toValue = (__bridge id _Nullable)(endRoundPath.CGPath);
    maskAnimation.duration = [self transitionDuration:transitionContext];
    maskAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [maskAnimation setValue:transitionContext forKey:@"transitionContext"];
    [maskLayer addAnimation:maskAnimation forKey:@"path"];
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    switch (self.transitionType)
    {
        case ZTransitionTypeShow:
        {
            idtransitionContext = [anim valueForKey:@"transitionContext"];
            [transitionContext completeTransition:YES];
        }
            break;
        case ZTransitionTypeDismiss:
        {
            idtransitionContext = [anim valueForKey:@"transitionContext"];
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
            if ([transitionContext transitionWasCancelled])
            {
                [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey].view.layer.mask = nil;;
            }
        }
            break;
        default:
            break;
    }
}

第二步:在通话界面实现相应的动画操作。
代码如下:

#import "TelephoneViewController.h"
#import "ViewController.h"
#import "ZTransition.h"
@interface TelephoneViewController ()

@end

@implementation TelephoneViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"Dismiss");


    UIToolbar *tools = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 64)];
    [self.view addSubview:tools];
}

- (instancetype)init
{
    self = [super init];
    if (self)
    {
        self.transitioningDelegate = self;
        self.modalTransitionStyle = UIModalPresentationCustom;
    }
    return self;
}

- (IBAction)dismissVC:(id)sender
{
    [self dismissViewControllerAnimated:YES completion:nil];
}


- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    return [ZTransition transitionWithType:ZTransitionTypeShow];
}

- (id)animationControllerForDismissedController:(UIViewController *)dismissed{
    return [ZTransition transitionWithType:ZTransitionTypeDismiss];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end

第三部分,最后效果图

QQ20170612-161637.gif

你可能感兴趣的:(利用转场动画来实现类似QQ语音通话界面隐藏和出现的效果)