背景
我們需要用到一個上下輕微晃動的動畫效果,提示有什麼東西,吸引用戶的注意。
方案一
- (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來實現動畫
- (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點之後,需要重新設置frame或者position?
答: 因爲anchorpoint設置爲(0,1)後,改變了之前默認的(0.5,0.5) - 改變anchorPoint後,能算出新的frame嗎
- 答: 可以,首先得算出最初的poisition,然後再計算
- 問: 具體步驟
- 答: 先算position,然後根據anchorpoint畫圖,再做計算,單方面改變anchorPoint一定會改變frame
- 問:如果父視圖變了,子視圖沒有變,子視圖的frame和bounds會變嗎
- 答:不變
- 問: 如果子視圖的anchorPoint也變了呢
- 答: 子視圖根據父視圖變化後的frame來計算