如下垫蛆,第一次看到陌陌的這個(gè)效果资锰,一半驚艷一半懵逼:動(dòng)畫(huà)確實(shí)有震驚的效果昏鹃,但是怎么實(shí)現(xiàn)的以清?
分解一下:
- 抖動(dòng)
- 添加黑白閃爍的半透明蒙層
- 用白色折線畫(huà)閃電
- 對(duì)UILabel截圖,圖斜劈成兩半本刽,后半部分平移后旋轉(zhuǎn)
- 在底部放張碎片的圖片
先寫(xiě)出基本的視圖赫冬,一個(gè)UIView對(duì)象用于設(shè)置圓角讽坏,背景顏色等等妇萄,一個(gè)UILabel對(duì)象用于顯示內(nèi)容:
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
self.bgView = [[UIView alloc] init];
self.bgView.backgroundColor = [UIColor colorWithRGB:0xADCCFF alpha:1];
self.bgView.left = kMainScreenWidth/2;
self.bgView.top = 100;
self.bgView.layer.cornerRadius = 4;
self.bgView.clipsToBounds = YES;
[self.view addSubview:self.bgView];
self.messageLabel = [[UILabel alloc] init];
self.messageLabel.text = @"臥槽震驚";
[self.messageLabel sizeToFit];
self.messageLabel.textAlignment = NSTextAlignmentCenter;
self.bgView.height = self.messageLabel.height + 20;
self.bgView.width = self.messageLabel.width + 30;
self.messageLabel.center = CGPointMake(self.bgView.width/2, self.bgView.height/2);
[self.bgView addSubview:self.messageLabel];
}
先看一個(gè)最難的蜕企,步驟4:
UILabel對(duì)象的截取
動(dòng)畫(huà)比較難的就是對(duì)label截取任意形狀的圖了。
思路:通過(guò)把顯示內(nèi)容的label冠句,截取成前后兩個(gè)梯形獲取對(duì)應(yīng)梯形圖片或者view轻掩,拼接兩個(gè)圖片,這樣動(dòng)畫(huà)之前看起來(lái)和單個(gè)label顯示沒(méi)有區(qū)別懦底。當(dāng)需要?jiǎng)赢?huà)的時(shí)候唇牧,后邊的梯形先向右平移幾個(gè)dp,然后向下旋轉(zhuǎn)幾度聚唐。具體平移和旋轉(zhuǎn)的數(shù)字可以根據(jù)效果自行調(diào)整丐重。
首先利用貝塞爾曲線和CAShapeLayer獲得自己想要的形狀。得到CAShapeLayer對(duì)象杆查,先看看長(zhǎng)什么樣子:
[self.messageLabel.layer addSublayer:shapeLayer];
添加完CAShapeLayer對(duì)象后:
黑色遮蓋部分就是CAShapeLayer對(duì)象弥臼,符合,形狀符合預(yù)期根灯。但是我想要的是遮蓋部分顯示,未遮蓋的“震驚”部分變透明掺栅。這就用到了CALayer的mask屬性烙肺。
該屬性也是一個(gè)CALayer對(duì)象。 簡(jiǎn)單理解就是:如果設(shè)置了CALayer對(duì)象mask屬性氧卧,那么當(dāng)前CALayer對(duì)象只能顯示被mask屬性遮蓋的部分桃笙,其余部分變透明——正好符合我們的預(yù)期:
self.messageLabel.layer.mask = shapeLayer;
通過(guò)對(duì)現(xiàn)在的UILabel對(duì)象截屏得一個(gè)只顯示前半部分梯形內(nèi)圖像后半部分透明的視圖snapshotView1,然后添加到self.bgView上:
UIView *snapshotView1 = [self.messageLabel snapshotViewAfterScreenUpdates:YES];
snapshotView1.center = CGPointMake(self.bgView.width/2, self.bgView.height/2);
[self.bgView addSubview:snapshotView1];
同理可得只顯示后半部分內(nèi)容前半部分透明的視圖snapshotView2沙绝,再添加到self.bgView上搏明。
實(shí)際上snapshotView1,snapshotView2和self.messageLabel的size是一樣的闪檬,所以將snapshotView1和snapshotView2的位置設(shè)置為一樣的就能得到和圖一一樣的視覺(jué)效果星著。
動(dòng)畫(huà)時(shí)斷裂效果代碼:
- (void)rupture {
CGAffineTransform transform = CGAffineTransformIdentity;
// 向右平移3dp
transform = CGAffineTransformTranslate(transform, 3, 0);
// 旋轉(zhuǎn)10度
transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 10.0);
self.snapshotView2.layer.affineTransform = transform;
}
抖動(dòng)
抖動(dòng)效果的實(shí)現(xiàn)就是使用了UIView提供的彈簧效果動(dòng)畫(huà):
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^__nullable)(BOOL finished))completion
就是這animations block里設(shè)置向上移動(dòng)5dp,因?yàn)閺椈尚Ч置酰瑫?huì)不停的抖動(dòng)
- (void)shake {
[UIView animateWithDuration:1.0 delay:0 usingSpringWithDamping:0.08 initialSpringVelocity:30 options:0 animations:^{
self.bgView.top = self.bgView.top-5;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.1 animations:^{
self.bgView.top = 100;
}];
// 抖動(dòng)結(jié)束斷裂
[self rupture];
// 顯示斷裂碎片
[self showSplinterView];
}];
}
黑白閃爍的背景
思路:往self.bgView上添加一個(gè)黑色半透明的視圖對(duì)象虚循,同時(shí)循環(huán)動(dòng)畫(huà)改變視圖對(duì)象的透明度。這樣就有了閃爍效果
# pragma mark - 添加黑白閃爍的背景蒙層
- (void)flashMask {
[self stopFlashMask];
self.flashMaskView = [[UIView alloc] initWithFrame:self.bgView.bounds];
self.flashMaskView.backgroundColor = [UIColor blackColor];
self.flashMaskView.alpha = 0.1;
[self.flashMaskView.layer addAnimation:[self opacityForever_Animation:0.1] forKey:nil];
[self.bgView addSubview:self.flashMaskView];
}
- (void)stopFlashMask {
if (self.flashMaskView && [self.flashMaskView superview]) {
[self.flashMaskView removeFromSuperview];
}
}
- (CABasicAnimation *)opacityForever_Animation:(float)time
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];//必須寫(xiě)opacity才行。
animation.fromValue = [NSNumber numberWithFloat:0.7f];
animation.toValue = [NSNumber numberWithFloat:0.2f];//這是透明度横缔。
animation.autoreverses = YES;
animation.duration = time;
animation.repeatCount = 3;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];///沒(méi)有的話是均勻的動(dòng)畫(huà)铺遂。
return animation;
}
閃電
思路:閃電就是白色的折線,盡量畫(huà)的寫(xiě)實(shí)一點(diǎn)就行了茎刚。
生成一個(gè)UIBezierPath對(duì)象襟锐,然后不停的調(diào)用addLineToPoint:方法添加一段一段的線,然后根據(jù)折線生成CAShapeLayer對(duì)象膛锭,給CAShapeLayer對(duì)象添加動(dòng)畫(huà)方法粮坞,使得折線動(dòng)畫(huà)出來(lái)而不是一下子全部出現(xiàn)
- (void)flash {
[self removeFlash];
UIBezierPath *path = [[UIBezierPath alloc] init];
[path moveToPoint:CGPointMake(self.bgView.width*5/9, 0)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9 - 3, self.bgView.height/10)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9, self.bgView.height/10 + self.bgView.height/7)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9 - 3, self.bgView.height/10 + self.bgView.height/7 + self.bgView.height/5)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9 - 3 - 4, self.bgView.height/10 + self.bgView.height/7 + self.bgView.height/5 + 2)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9 - 3 - 4 - 1, self.bgView.height/10 + self.bgView.height/7 + self.bgView.height/5 + 2 + 2)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9 - 3 - 4 - 1 + self.bgView.width/20, self.bgView.height/10 + self.bgView.height/7 + self.bgView.height/5 + 2 + 2 + self.bgView.height/7)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9 - 3 - 4 - 1 + self.bgView.width/20 - 3, self.bgView.height/10 + self.bgView.height/7 + self.bgView.height/5 + 2 + 2 + self.bgView.height/7 + 2)];
[path addLineToPoint:CGPointMake(self.bgView.width*5/9+self.bgView.width/9 - 3 - 4 - 1 + self.bgView.width/20 , self.bgView.height/10 + self.bgView.height/7 + self.bgView.height/5 + 2 + 2 + self.bgView.height/7 + 3)];
self.flashLayer = [CAShapeLayer layer];
self.flashLayer.strokeColor = [UIColor whiteColor].CGColor;
self.flashLayer.fillColor = [UIColor clearColor].CGColor;
self.flashLayer.path = path.CGPath;
[self.bgView.layer addSublayer:self.flashLayer];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
pathAnimation.duration = 0.3;
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
pathAnimation.repeatCount = 1;
pathAnimation.delegate = self;
[self.flashLayer addAnimation:pathAnimation forKey:nil];
}
把以上幾種效果,適當(dāng)組合一下就山寨個(gè)差不多了泉沾。