iOS實(shí)現(xiàn)一個(gè)陌陌聊天里的“震驚”效果

如下垫蛆,第一次看到陌陌的這個(gè)效果资锰,一半驚艷一半懵逼:動(dòng)畫(huà)確實(shí)有震驚的效果昏鹃,但是怎么實(shí)現(xiàn)的以清?


陌陌震驚.gif

分解一下:

  1. 抖動(dòng)
  2. 添加黑白閃爍的半透明蒙層
  3. 用白色折線畫(huà)閃電
  4. 對(duì)UILabel截圖,圖斜劈成兩半本刽,后半部分平移后旋轉(zhuǎn)
  5. 在底部放張碎片的圖片

先寫(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];
}
圖一.png

先看一個(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ì)象后:


添加后的樣子.png

黑色遮蓋部分就是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;
完美的前半部分梯形.png

通過(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è)差不多了泉沾。

demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捞蚂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子跷究,更是在濱河造成了極大的恐慌姓迅,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件俊马,死亡現(xiàn)場(chǎng)離奇詭異丁存,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)柴我,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)解寝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人艘儒,你說(shuō)我怎么就攤上這事聋伦。” “怎么了界睁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵觉增,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我翻斟,道長(zhǎng)逾礁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任访惜,我火速辦了婚禮嘹履,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘债热。我一直安慰自己砾嫉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布窒篱。 她就那樣靜靜地躺著焰枢,像睡著了一般蚓峦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上济锄,一...
    開(kāi)封第一講書(shū)人閱讀 51,737評(píng)論 1 305
  • 那天暑椰,我揣著相機(jī)與錄音,去河邊找鬼荐绝。 笑死一汽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的低滩。 我是一名探鬼主播召夹,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼恕沫!你這毒婦竟也來(lái)了监憎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤婶溯,失蹤者是張志新(化名)和其女友劉穎鲸阔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體迄委,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡褐筛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叙身。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渔扎。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖信轿,靈堂內(nèi)的尸體忽然破棺而出晃痴,到底是詐尸還是另有隱情,我是刑警寧澤财忽,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布倘核,位于F島的核電站,受9級(jí)特大地震影響定罢,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旁瘫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一祖凫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧酬凳,春花似錦惠况、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春权埠,著一層夾襖步出監(jiān)牢的瞬間榨了,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工攘蔽, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留龙屉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓满俗,卻偏偏與公主長(zhǎng)得像转捕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唆垃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 在進(jìn)行知行合一挑戰(zhàn)的過(guò)程中五芝,我們聽(tīng)到最多的三個(gè)障礙,分別是:沒(méi)錢(qián)辕万、沒(méi)時(shí)間枢步、沒(méi)辦法。 前兩回分別說(shuō)了“沒(méi)錢(qián)”和“沒(méi)時(shí)...
    大胡子逸舟閱讀 247評(píng)論 0 0
  • 【感悟】 1蓄坏、有幾條不變的鐵律 早上剛被鬧鐘叫醒 總是覺(jué)得離不開(kāi)床价捧。其實(shí)只要立即起床,然后也就沒(méi)有離不開(kāi)床這一念頭...
    i期待閱讀 270評(píng)論 0 0
  • 她像一縷喝醉的風(fēng)在我眼前飄著,火光里沒(méi)有她的影子渔彰。 她張開(kāi)雙臂從我身體穿過(guò)去嵌屎,像一個(gè)擁抱,一陣舒適的冷冰恍涂。 她在我...
    貝龍閱讀 845評(píng)論 24 8