iOS实现一个轻微晃动的提示动画

背景

我们需要用到一个上下轻微晃动的动画效果,提示有什么东西,吸引用户的注意。

方案一

- (UIButton *)moveBtn {
  if (!_moveBtn) {
   _moveBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  _moveBtn.frame = CGRectMake(0,0 ,300,150);
   _moveBtn.enabled = NO;
    [_moveBtn setBackgroundImage:[UIImage imageNamed:@"yangmi"] forState:UIControlStateDisabled];
    [_moveBtn setTitleColor:[UIColor redColor] forState:(UIControlStateNormal)];
    _moveBtn.titleLabel.font = [UIFont systemFontOfSize:10];
    _moveBtn.layer.masksToBounds = YES;
    _moveBtn.layer.cornerRadius = 5.f;
    CGFloat width = [UIScreen mainScreen].bounds.size.width;
    CGFloat height = [UIScreen mainScreen].bounds.size.height;
    _moveBtn.layer.anchorPoint = CGPointMake(0, 1);
    //这句代码改变了上面原始的frame,这个时候可以设置position
    //也可以设置frame
    //_moveBtn.frame = CGRectMake(width / 2.f - 150,height / 2.f - 75 ,300,150);
    _moveBtn.layer.position = CGPointMake(width / 2.f - 150, height/2.f + 75);
    ///这个点设置很关键,可以设置摇动的锚点,同时让这个按钮屏幕居中
  }
  return _moveBtn;
}

- (void)shakeAnimationForViewQ:(UIButton *)btn{
    CGFloat secsAngle = M_PI / 30.f;
    [self showAnimationWithTime:secsAngle];
}

- (void)showAnimationWithTime:(CGFloat)angle {
    self.moveBtn.layer.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        CGFloat secsAngle1;
        if (angle > 0) {
            secsAngle1 = -M_PI / 15.f;
        }else{
            secsAngle1 = M_PI / 15.f;
        }
        [self showAnimationWithTime:secsAngle1];
    });
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.moveBtn];
    [self shakeAnimationForViewQ:self.moveBtn];
}

效果图

幂幂的性感

第二种方案

起因:上面的方案用transform实现,有点僵硬,动画看上去不是很好,接下来用CAKeyframeAnimation来实现动画

#define radian(angle) ((angle) / 180.0 * M_PI)

- (UIButton *)moveBtn {
  if (!_moveBtn) {
   _moveBtn = [UIButton buttonWithType:UIButtonTypeCustom];
       _moveBtn.frame = CGRectMake(0, 0, 300, 150);
   _moveBtn.enabled = NO;
    [_moveBtn setBackgroundImage:[UIImage imageNamed:@"yangmi"] forState:UIControlStateDisabled];
    [_moveBtn setTitleColor:[UIColor whiteColor] forState:(UIControlStateNormal)];
    _moveBtn.titleLabel.font = [UIFont systemFontOfSize:30];
    [_moveBtn setTitle:@"我就是很美" forState:UIControlStateNormal];
    [_moveBtn setContentHorizontalAlignment:UIControlContentHorizontalAlignmentRight];
    _moveBtn.layer.anchorPoint = CGPointMake(0, 1);
    _moveBtn.layer.masksToBounds = YES;
    _moveBtn.layer.cornerRadius = 5.f;
      CGFloat width = [UIScreen mainScreen].bounds.size.width;
      CGFloat height = [UIScreen mainScreen].bounds.size.height;
     _moveBtn.layer.position = CGPointMake(width / 2.f - 150, height/2.f + 75);
    ///这个点设置很关键,可以设置摇动的锚点,这个设置动画在中间
  }
  return _moveBtn;
}

#pragma mark

- (void)addMoveAnimation:(UIView *)view{
 CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
 animation.delegate = self;
 animation.keyPath = @"transform.rotation";
 animation.values = @[@(radian(0)), @(radian(-20)), @(radian(0)), @(radian(-20)),@(radian(0))];
 animation.duration = 0.7;
 // 动画的重复执行次数
 animation.repeatCount = 1;
 // 保持动画执行完毕后的状态
 animation.removedOnCompletion = NO;
 animation.fillMode = kCAFillModeForwards;
 [view.layer addAnimation:animation forKey:@"shake_animation"];
}

#pragma mark -- 动画代理
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self addMoveAnimation:self.moveBtn];
 });
}

#pragma mark - 移除抖动动画

- (void)removeAnimationShakeWithView:(UIView *)view{
 //结束动画
 [view.layer removeAnimationForKey:@"shake"];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.moveBtn];
    [self addMoveAnimation:self.moveBtn];
}

效果图

自信的杨幂

重要概念

  • anchorpoint
    相当于能旋转画的钉子
  • position
    anchorpoint在父layer上的坐标点
  • 指定position相当于指定了锚点
  • position点是相对suerLayer的,anchorPoint点是相对自己layer的,两者是相对不同的坐标空间的一个重合点。

思考题

  • 问:为什么在设置为anchorpoint点之后,需要重新设置frame或者position?
    答: 因为anchorpoint设置为(0,1)后,改变了之前默认的(0.5,0.5)
  • 改变anchorPoint后,能算出新的frame吗
  • 答: 可以,首先得算出最初的poisition,然后再计算
  • 问: 具体步骤
  • 答: 先算position,然后根据anchorpoint画图,再做计算,单方面改变anchorPoint一定会改变frame
  • 问:如果父视图变了,子视图没有变,子视图的frame和bounds会变吗
  • 答:不变
  • 问: 如果子视图的anchorPoint也变了呢
  • 答: 子视图根据父视图变化后的frame来计算

2023年5月14学习
1、改变了anchorpoint不会改变position值
2、改变anchorpoint会让视图移动,要想让视图回到原先位置,就需要改动position
3、position.x = originframe.origin.x + anchorPoint.x * bounds.size.width;
position.y = originframe.origin.y + anchorPoint.y * bounds.size.height;
怎么计算posision,原先的x和y,加上后面的值
4、我们要解释的anchorPoint就相当于白纸上的图钉,它主要的作用就是用来作为变换的支点,旋转就是一种变换,类似的还有平移、缩放。(摘自下面的文章)

参考文章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值