美文网首页
iOS切换动画

iOS切换动画

作者: HCL黄 | 来源:发表于2019-10-09 12:01 被阅读0次
动画.gif

废话不多说,直接上代码

@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

相关文章

网友评论

      本文标题:iOS切换动画

      本文链接:https://www.haomeiwen.com/subject/hpnwpctx.html