iOS切换动画
2019-10-09 本文已影响0人
HCL黄

废话不多说,直接上代码
@protocol HHSwitchAnimationDelegate <NSObject>
- (void)didClickListWithType:(NSString *)type;
@end
@interface HHSwitchAnimation : UIView
@property (nonatomic, weak) id<HHSwitchAnimationDelegate> delegate;
@end
@interface HHButton : UIButton
/** 标志:选中为1 未选中为0 */
@property (nonatomic, assign) NSInteger index;
/** 缩放的初始值 */
@property (nonatomic, assign) CGFloat scaleFromValue;
/** 缩放的结束值 */
@property (nonatomic, assign) CGFloat scaleToValue;
/** 透明的初始值 */
@property (nonatomic, assign) CGFloat alphaFromValue;
/** 透明的结束值 */
@property (nonatomic, assign) CGFloat alphaToValue;
@end
@implementation HHButton
@end
@interface HHSwitchAnimation ()
<
CAAnimationDelegate
>
@property (strong, nonatomic) HHButton *btn1;
@property (strong, nonatomic) HHButton *btn2;
@property (nonatomic, assign) BOOL isAnimation;
@end
static CGFloat btnW = 45;
static CGFloat btnH = 25;
static NSString *dayKeyValue = @"today";
static NSString *allKeyValue = @"total";
@implementation HHSwitchAnimation
-(void)dealloc {
[self.btn1.layer removeAllAnimations];
[self.btn2.layer removeAllAnimations];
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setupUI];
[self setupUserAction];
}
return self;
}
- (void)setupUI {
self.backgroundColor = [UIColor blackColor];
// 基本配置
[self setupShadowView:self.btn1 shadowColor:[UIColor blackColor] shadowRadius:4 shadowOpacity:0.5 shadowOffset:CGSizeMake(0, 2)];
[self setupShadowView:self.btn2 shadowColor:[UIColor blackColor] shadowRadius:4 shadowOpacity:0.5 shadowOffset:CGSizeMake(0, 2)];
[self.btn1 setTitle:@"日榜" forState:0];
[self.btn2 setTitle:@"总榜" forState:0];
[self.btn1 setTitleColor:[UIColor whiteColor] forState:0];
self.btn1.titleLabel.font = [UIFont systemFontOfSize:14];
[self.btn1 setBackgroundImage:[UIImage imageNamed:@"icon_unSelected"] forState:0];
[self.btn2 setTitleColor:[UIColor whiteColor] forState:0];
self.btn2.titleLabel.font = [UIFont systemFontOfSize:14];
[self.btn2 setBackgroundImage:[UIImage imageNamed:@"icon_unSelected"] forState:0];
// 默认选中第一个按钮,不选中第二个按钮
[self setupSelectedButton:self.btn1];
[self setupUnSelectedButton:self.btn2];
self.isAnimation = NO;
}
- (void)setupUserAction {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction)];
[self addGestureRecognizer:tap];
}
- (void)tapAction {
// 正在动画就return
if (self.isAnimation) { return; }
self.isAnimation = YES;
NSString *type = @"today";
CGPoint P1 = self.btn1.center;
CGPoint P2 = self.btn2.center;
if (self.btn1.index == 1) {
type = @"total";
// 日榜在前面
[self moveView:self.btn1 fromPoint:P1 toPoint:P2 keyValue:dayKeyValue delegate:self];
[self moveView:self.btn2 fromPoint:P2 toPoint:P1 keyValue:allKeyValue delegate:nil];
}
else {
// 总榜在前面
[self moveView:self.btn1 fromPoint:P1 toPoint:P2 keyValue:dayKeyValue delegate:nil];
[self moveView:self.btn2 fromPoint:P2 toPoint:P1 keyValue:allKeyValue delegate:self];
}
if (self.delegate && [self.delegate respondsToSelector:@selector(didClickListWithType:)]) {
[self.delegate didClickListWithType:type];
}
}
- (void)setupSelectedButton:(HHButton *)button {
// 消除在原有基础上扩大0.3倍问题
button.transform = CGAffineTransformMakeScale(1.0, 1.0);
// frame可以根据自己需要进行调整
button.frame = CGRectMake(104 - btnW - 16, 4, btnW, btnH);
button.index = 1;
button.scaleFromValue = 1.0;
button.scaleToValue = 0.7;
button.alphaFromValue = 1.0;
// 这个值最好跟未选中的alpha对应,这样就不会闪一下
button.alphaToValue = 0.4;
button.alpha = 1.0;
[self addSubview:button];
}
- (void)setupUnSelectedButton:(HHButton *)button {
// frame可以根据自己需要进行调整
button.frame = CGRectMake(104 - btnW - 45, 16, btnW, btnH);
button.index = 0;
button.scaleFromValue = 0.7;
button.scaleToValue = 1.0;
// 这个值最好跟未选中的alpha对应,这样就不会闪一下
button.alphaFromValue = 0.4;
button.alphaToValue = 1.0;
button.alpha = 0.4;
button.transform = CGAffineTransformMakeScale(0.7, 0.7);
[self addSubview:button];
}
- (void)moveView:(HHButton *)view fromPoint:(CGPoint)fromP toPoint:(CGPoint)toP keyValue:(NSString *)keyValue delegate:(id)delegate {
CGFloat controlY = toP.y;
CGFloat controlX = fromP.x;
CGPoint controlPoint = CGPointMake(controlX, controlY);
// 创建贝塞尔路径
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:fromP];
[path addQuadCurveToPoint:toP controlPoint:controlPoint];
// 路径动画
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.path = path.CGPath;
// 缩放动画
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.fromValue = @(view.scaleFromValue);
scaleAnimation.toValue = @(view.scaleToValue);
// 透明动画
CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
alphaAnimation.fromValue = @(view.alphaFromValue);
alphaAnimation.toValue = @(view.alphaToValue);
// 动画组
CAAnimationGroup *group = [CAAnimationGroup animation];
group.duration = 0.75f;
group.repeatCount = 1;
group.delegate = delegate;
group.removedOnCompletion = NO; // 取消反弹
group.fillMode = kCAFillModeForwards; // 始终保持最新的效果
group.timingFunction= [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; // 先慢后快
group.animations = @[animation, scaleAnimation, alphaAnimation];
[group setValue:keyValue forKey:@"AnimationKey"];
[view.layer addAnimation:group forKey:nil];
}
#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if ([[anim valueForKey:@"AnimationKey"] isEqualToString:dayKeyValue]) { // 切换总榜到前面
[self setupUnSelectedButton:self.btn1];
[self setupSelectedButton:self.btn2];
} else { // 切换日榜在前面
[self setupUnSelectedButton:self.btn2];
[self setupSelectedButton:self.btn1];
}
[self.btn1.layer removeAllAnimations];
[self.btn2.layer removeAllAnimations];
self.isAnimation = NO;
}
#pragma mark - Private Method
- (void)setupShadowView:(UIView *)view
shadowColor:(UIColor *)color
shadowRadius:(CGFloat)radius
shadowOpacity:(CGFloat)opacity
shadowOffset:(CGSize)offset{
view.layer.shadowColor = color.CGColor;
view.layer.shadowRadius = radius;
view.layer.shadowOpacity = opacity;
view.layer.shadowOffset = offset;
}
#pragma mark - Property
- (HHButton *)btn1 {
if (_btn1 == nil) {
_btn1 = [[HHButton alloc] init];
_btn1.userInteractionEnabled = NO;
}
return _btn1;
}
- (HHButton *)btn2 {
if (_btn2 == nil) {
_btn2 = [[HHButton alloc] init];
_btn2.userInteractionEnabled = NO;
}
return _btn2;
}
@end