diff --git a/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.h b/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.h index 5274a157..a4980010 100644 --- a/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.h +++ b/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.h @@ -30,9 +30,6 @@ - (BOOL)isAnimating; @end - -// TODO: 实现多种animation类型 - typedef NS_ENUM(NSInteger, QMUIToastAnimationType) { QMUIToastAnimationTypeFade = 0, QMUIToastAnimationTypeZoom, diff --git a/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.m b/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.m index dd5a54fa..133d3164 100644 --- a/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.m +++ b/QMUIKit/QMUIComponents/ToastView/QMUIToastAnimator.m @@ -17,10 +17,14 @@ #import "QMUICore.h" #import "QMUIToastView.h" -@interface QMUIToastAnimator () +#define kSlideAnimationKey @"kSlideAnimationKey" + +@interface QMUIToastAnimator () + +@property (nonatomic, assign) BOOL isShowing; +@property (nonatomic, assign) BOOL isAnimating; +@property (nonatomic, copy) void (^basicAnimationCompletion)(BOOL finished); -@property(nonatomic, assign) BOOL isShowing; -@property(nonatomic, assign) BOOL isAnimating; @end @implementation QMUIToastAnimator @@ -45,11 +49,62 @@ - (instancetype)initWithToastView:(QMUIToastView *)toastView { - (void)showWithCompletion:(void (^)(BOOL finished))completion { self.isShowing = YES; + switch (self.animationType) { + case QMUIToastAnimationTypeZoom:{ + [self zoomAnimationForShow:YES withCompletion:completion]; + } + break; + case QMUIToastAnimationTypeSlide:{ + [self slideAnimationForShow:YES withCompletion:completion]; + } + break; + case QMUIToastAnimationTypeFade: + default:{ + [self fadeAnimationForShow:YES withCompletion:completion]; + } + break; + } +} + +- (void)hideWithCompletion:(void (^)(BOOL finished))completion { + self.isShowing = NO; + switch (self.animationType) { + case QMUIToastAnimationTypeZoom:{ + [self zoomAnimationForShow:NO withCompletion:completion]; + } + break; + case QMUIToastAnimationTypeSlide:{ + [self slideAnimationForShow:NO withCompletion:completion]; + } + break; + case QMUIToastAnimationTypeFade: + default:{ + [self fadeAnimationForShow:NO withCompletion:completion]; + } + break; + } +} + +- (void)zoomAnimationForShow:(BOOL)show withCompletion:(void (^)(BOOL))completion { + CGFloat alpha = show ? 1.f : 0.f; + CGAffineTransform small = CGAffineTransformMakeScale(0.5f, 0.5f); + CGAffineTransform endTransform = show ? CGAffineTransformIdentity : small; self.isAnimating = YES; - [UIView animateWithDuration:0.25 delay:0.0 options:QMUIViewAnimationOptionsCurveOut|UIViewAnimationOptionBeginFromCurrentState animations:^{ - self.toastView.backgroundView.alpha = 1.0; - self.toastView.contentView.alpha = 1.0; + if (show) { + self.toastView.backgroundView.transform = small; + self.toastView.contentView.transform = small; + } + [UIView animateWithDuration:0.25 + delay:0.0 + options:QMUIViewAnimationOptionsCurveOut|UIViewAnimationOptionBeginFromCurrentState + animations:^{ + self.toastView.backgroundView.alpha = alpha; + self.toastView.contentView.alpha = alpha; + self.toastView.backgroundView.transform = endTransform; + self.toastView.contentView.transform = endTransform; } completion:^(BOOL finished) { + self.toastView.backgroundView.transform = endTransform; + self.toastView.contentView.transform = endTransform; self.isAnimating = NO; if (completion) { completion(finished); @@ -57,12 +112,27 @@ - (void)showWithCompletion:(void (^)(BOOL finished))completion { }]; } -- (void)hideWithCompletion:(void (^)(BOOL finished))completion { - self.isShowing = NO; +- (void)slideAnimationForShow:(BOOL)show withCompletion:(void (^)(BOOL))completion { + self.basicAnimationCompletion = [completion copy]; + self.isAnimating = YES; + if (show) { + [self showSlideAnimationOnView:self.toastView.backgroundView withIndentifier:@"showBackgroundView"]; + [self showSlideAnimationOnView:self.toastView.contentView withIndentifier:@"showContentView"]; + }else{ + [self hideSlideAnimationOnView:self.toastView.backgroundView withIndentifier:@"hideBackgroundView"]; + [self hideSlideAnimationOnView:self.toastView.contentView withIndentifier:@"hideContentView"]; + } +} + +- (void)fadeAnimationForShow:(BOOL)show withCompletion:(void (^)(BOOL))completion { + CGFloat alpha = show ? 1.f : 0.f; self.isAnimating = YES; - [UIView animateWithDuration:0.25 delay:0.0 options:QMUIViewAnimationOptionsCurveOut|UIViewAnimationOptionBeginFromCurrentState animations:^{ - self.toastView.backgroundView.alpha = 0.0; - self.toastView.contentView.alpha = 0.0; + [UIView animateWithDuration:0.25 + delay:0.0 + options:QMUIViewAnimationOptionsCurveOut|UIViewAnimationOptionBeginFromCurrentState + animations:^{ + self.toastView.backgroundView.alpha = alpha; + self.toastView.contentView.alpha = alpha; } completion:^(BOOL finished) { self.isAnimating = NO; if (completion) { @@ -71,6 +141,87 @@ - (void)hideWithCompletion:(void (^)(BOOL finished))completion { }]; } +- (void)showSlideAnimationOnView:(UIView *)popupView withIndentifier:(NSString *)key { + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"]; + animation.fromValue = [NSNumber numberWithFloat:- [[UIScreen mainScreen] bounds].size.height / 2 - popupView.frame.size.height / 2]; + animation.toValue = [NSNumber numberWithFloat:0]; + animation.duration = 0.6; + animation.delegate = self; + animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeBoth; + animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.51 : 1.24 : 0.02 : 0.99]; + [animation setValue:key forKey:kSlideAnimationKey]; + [popupView.layer addAnimation:animation forKey:@"showPopupView"]; + + CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.fromValue = [NSNumber numberWithFloat:0.0]; + opacityAnimation.toValue = [NSNumber numberWithFloat:1]; + opacityAnimation.duration = 0.27; + opacityAnimation.beginTime=CACurrentMediaTime() + 0.03; + opacityAnimation.removedOnCompletion = NO; + opacityAnimation.fillMode = kCAFillModeBoth; + opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 : 0.1: 0.25 : 1]; + + [popupView.layer addAnimation:opacityAnimation forKey:@"showOpacityKey"]; + + CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + rotateAnimation.fromValue = [NSNumber numberWithFloat:2 * M_PI/180]; + rotateAnimation.toValue = [NSNumber numberWithFloat:0]; + rotateAnimation.duration = 0.17; + rotateAnimation.beginTime=CACurrentMediaTime() + 0.26; + rotateAnimation.removedOnCompletion = NO; + rotateAnimation.fillMode = kCAFillModeBoth; + rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 : 0.1 : 0.25 : 1]; + + [popupView.layer addAnimation:rotateAnimation forKey:@"showRotateKey"]; +} + +- (void)hideSlideAnimationOnView:(UIView *)popupView withIndentifier:(NSString *)key { + CABasicAnimation *animationY = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"]; + animationY.fromValue = [NSNumber numberWithFloat:0]; + animationY.toValue = [NSNumber numberWithFloat:[[UIScreen mainScreen] bounds].size.height/2+popupView.frame.size.height/2]; + animationY.duration = 0.7; + animationY.removedOnCompletion = NO; + animationY.fillMode = kCAFillModeBoth; + animationY.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.73 : -0.38 : 0.03 : 1.41]; + animationY.delegate = self; + [animationY setValue:key forKey:kSlideAnimationKey]; + [popupView.layer addAnimation:animationY forKey:@"hidePopupView"]; + + CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; + rotateAnimation.fromValue = [NSNumber numberWithFloat:0]; + rotateAnimation.toValue = [NSNumber numberWithFloat:3 * M_PI/180]; + rotateAnimation.duration = 0.4; + rotateAnimation.beginTime=CACurrentMediaTime() + 0.05; + rotateAnimation.removedOnCompletion = NO; + rotateAnimation.fillMode = kCAFillModeBoth; + rotateAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.25 : 0.1 : 0.25 : 1]; + + [popupView.layer addAnimation:rotateAnimation forKey:@"hideRotateKey"]; + + + CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.fromValue = [NSNumber numberWithFloat:1]; + opacityAnimation.toValue = [NSNumber numberWithFloat:0]; + opacityAnimation.duration = 0.25; + opacityAnimation.beginTime=CACurrentMediaTime() + 0.15; + opacityAnimation.removedOnCompletion = NO; + opacityAnimation.fillMode = kCAFillModeBoth; + opacityAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.53 : 0.92 : 1 : 1]; + + [popupView.layer addAnimation:opacityAnimation forKey:@"hideOpacityKey"]; +} + +- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag { + if([[animation valueForKey:kSlideAnimationKey] isEqual:@"showContentView"] || + [[animation valueForKey:kSlideAnimationKey] isEqual:@"hideContentView"]) { + if (self.basicAnimationCompletion) { + self.basicAnimationCompletion(flag); + } + self.isAnimating = NO; + } +} + - (BOOL)isShowing { return self.isShowing; }