直播APP常用動(dòng)畫(huà)效果

介紹

記錄、總結(jié)開(kāi)發(fā)遇到一些問(wèn)題,大家一起交流學(xué)習(xí)。
這次帶來(lái),對(duì)直播APP的常用動(dòng)畫(huà)總結(jié)。
直播Live

效果展示

下面是一個(gè)很多平臺(tái)都有的入門(mén)豪華禮物動(dòng)畫(huà)——煙花。
一個(gè)復(fù)雜的禮物動(dòng)畫(huà),首先是美術(shù)給出gif實(shí)現(xiàn)草圖素材,技術(shù)進(jìn)行動(dòng)畫(huà)剖析圖片壓縮,在程序中加載圖片實(shí)現(xiàn)動(dòng)畫(huà),其中要注意內(nèi)存和CPU占用

煙花

圖片壓縮、加載與裁剪

1、圖片壓縮

美術(shù)給出的圖片,即使是壓縮過(guò),仍存在較大的壓縮空間,可以用這里或者更好的大小優(yōu)化。

2、圖片加載

主要有-imageNamed:-imageWithContentsOfFile:兩種方式。
AnimationImageCache類(lèi)是一個(gè)動(dòng)畫(huà)圖片加載類(lèi),用單例實(shí)現(xiàn)且內(nèi)部用NSCache持有引用。

注意,當(dāng)收到內(nèi)存不足警告時(shí),NSCache會(huì)自動(dòng)釋放內(nèi)存。所以每次訪(fǎng)問(wèn)NSCache,即使上一次已經(jīng)加載過(guò),也需要判斷返回值是否為空。

3、圖片裁剪

為了減少圖片資源的大小,有時(shí)候會(huì)把多個(gè)幀動(dòng)畫(huà)做成連續(xù)的一張圖。這時(shí)需要程序加載一整張資源圖,并在相應(yīng)的位置進(jìn)行裁剪。

    UIImage* sourceImage = [UIImage imageNamed:@"image/animation/gift_boat"];
    CGSize sourceSize = sourceImage.size;
    CGImageRef cgimage = CGImageCreateWithImageInRect(sourceImage.CGImage,
                                                      CGRectMake(0, 0, const_position_boat_x, sourceSize.height));
    gWaveFrameImage = [UIImage imageWithCGImage:cgimage];
    CGImageRelease(cgimage);
    cgimage = CGImageCreateWithImageInRect(sourceImage.CGImage,
                                           CGRectMake(const_position_boat_x, 0, const_position_boat_width, sourceSize.height));
    gBoatFrameImage = [UIImage imageWithCGImage:cgimage];
    CGImageRelease(cgimage);
    cgimage = CGImageCreateWithImageInRect(sourceImage.CGImage,
                                           CGRectMake(const_position_boat_x + const_position_boat_width, 0, sourceSize.width - const_position_boat_x - const_position_boat_width, sourceSize.height));
    gShadowFrameImage = [UIImage imageWithCGImage:cgimage];
    CGImageRelease(cgimage);

動(dòng)畫(huà)剖析與時(shí)間軸

下面這個(gè)是一個(gè)全屏類(lèi)型的“天使”禮物動(dòng)畫(huà),我們來(lái)剖析下這個(gè)動(dòng)畫(huà)的構(gòu)成。

  • 1、背景變暗,出現(xiàn)星空;
  • 2、流星劃過(guò)、月亮出現(xiàn)、云彩飄動(dòng);
  • 3、兩側(cè)浮空島震動(dòng),中間浮空島出現(xiàn);
  • 4、背光出現(xiàn),天使落下,翅膀扇動(dòng);
  • 5、星星閃爍、鳳凰出現(xiàn);
  • 6、漸隱消失;
天使

時(shí)間軸實(shí)現(xiàn)

為了讓動(dòng)畫(huà)按照時(shí)間順序一一執(zhí)行,可以把動(dòng)畫(huà)按時(shí)間和對(duì)象分成多個(gè)方法,通過(guò)GCD在指定的時(shí)間調(diào)用。

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self playMeteorAnimation];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self playLandAnimation];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self playLightAnimation];
    });
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(7.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self playStarAnimation];
    });

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(TOTAL_TIME * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        @weakify(self);
        [UIView animateWithDuration:0.5 animations:^{
            self.alpha = 0;
        } completion:^(BOOL finished) {
            @strongify(self);
            [self removeFromSuperview];
            [self callBackManager];
        }];
    });

常用動(dòng)畫(huà)效果

1、視圖變暗、變大

alpha值屬性是透明度,把背景設(shè)置成淡黑色,然后調(diào)整alpha可以達(dá)到背景漸變的視圖效果;
UIView的transform是可以用仿射變換矩陣來(lái)控制平移、放大縮小等。

    [UIView animateWithDuration:1.5 animations:^{
        self.mBackgroundView.alpha = 0.5;
        self.mAngelView.transform = CGAffineTransformMakeScale(1.2, 1.2);
    }];

2、勻速運(yùn)動(dòng)、交錯(cuò)效果

right是項(xiàng)目封裝的一個(gè)屬性,本質(zhì)是對(duì)UIView的frame進(jìn)行操作;
兩朵云, 左邊的朝右,右邊的朝左,即可達(dá)到交錯(cuò)的效果。

   [UIView animateWithDuration:TOTAL_TIME delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        self.mAngelCloudView0.right += 250;
        self.mAngelCloudView1.right -= 190;
    } completion:nil];

3、上下往返運(yùn)動(dòng)

CAKeyframeAnimation是關(guān)鍵幀動(dòng)畫(huà),對(duì)layer的postion的y坐標(biāo)進(jìn)行操作;
設(shè)定好起始位置、經(jīng)過(guò)位置,最后回到起始位置,即可實(shí)現(xiàn)上下往返的效果。

    CAKeyframeAnimation *upDownAnimation;
    upDownAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position.y"];
    upDownAnimation.values = @[@(self.mAngelLandView1.layer.position.y), @(self.mAngelLandView1.layer.position.y + 5), @(self.mAngelLandView1.layer.position.y)];
    upDownAnimation.duration = 2;
    upDownAnimation.fillMode = kCAFillModeBoth;
    upDownAnimation.calculationMode = kCAAnimationCubic;
    upDownAnimation.repeatCount = HUGE_VALF;
    [self.mAngelLandView1.layer addAnimation:upDownAnimation forKey:@"upDownAnimation"];
    

4、閃爍效果

閃爍的本質(zhì)是alpha的變化,但是UIView的block動(dòng)畫(huà)不好實(shí)現(xiàn)重復(fù)效果;
UIView的alpha對(duì)應(yīng)的是layer的opacity屬性,設(shè)定好起始、過(guò)度和結(jié)束的狀態(tài),實(shí)現(xiàn)閃爍的效果。

    CAKeyframeAnimation *opacityAnimation;
    opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
    opacityAnimation.values = @[@(0), @(1), @(0)];
    opacityAnimation.duration = 1.5;
    opacityAnimation.fillMode = kCAFillModeBoth;
    opacityAnimation.calculationMode = kCAAnimationCubic;
    opacityAnimation.repeatCount = HUGE_VALF;
    [self.mAngelStarView.layer addAnimation:opacityAnimation forKey:@"opacityAnimation"];

5、貝塞爾曲線(xiàn)運(yùn)動(dòng)

貝塞爾曲線(xiàn)是優(yōu)化動(dòng)畫(huà)體驗(yàn)的很重要部分,比如說(shuō)天上掉下來(lái)的羽毛,地上冒起來(lái)的氣泡,空中飄蕩的氣球,都可以用貝塞爾曲線(xiàn)來(lái)繪制,從而獲得很好的視覺(jué)體驗(yàn);
本質(zhì)還是關(guān)鍵幀動(dòng)畫(huà),這次操作的屬性是position,通過(guò)path屬性來(lái)確定路徑;
給貝塞爾曲線(xiàn)設(shè)定好目標(biāo)點(diǎn)后,把path賦值給關(guān)鍵幀動(dòng)畫(huà),再把動(dòng)畫(huà)添加到layer上即可;

    UIImage *image = [[AnimationImageCache shareInstance] getImageWithName:@"gift_castle_hot_air_balloon3.png"];
    UIImageView *hotAirBalloonView0 = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, image.size.width / 2, image.size.height / 2)];
    [self addSubview:hotAirBalloonView0];
    [hotAirBalloonView0 setImage:image];
    // 飄動(dòng)
    CGPoint position = CGPointMake(self.width, hotAirBalloonView0.top);
    CGFloat duration = 5;
    CAKeyframeAnimation *positionAnimate = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    positionAnimate.repeatCount = 1;
    positionAnimate.duration = duration;
    positionAnimate.fillMode = kCAFillModeForwards;
    positionAnimate.removedOnCompletion = NO;
    UIBezierPath *sPath = [UIBezierPath bezierPath];
    [sPath moveToPoint:position];
    [sPath addCurveToPoint:CGPointMake(-image.size.width / 2, position.y) controlPoint1:CGPointMake(self.width / 3 * 2, position.y - 60) controlPoint2:CGPointMake(self.width / 3, position.y + 60)];
    positionAnimate.path = sPath.CGPath;
    [hotAirBalloonView0.layer addAnimation:positionAnimate forKey:@"positionAnimate"];

6、遮罩動(dòng)畫(huà)

遮罩效果可以實(shí)現(xiàn)彩虹??出現(xiàn)、煙花爆炸、畫(huà)卷打開(kāi)等效果,通過(guò)改變遮罩的大小,影響原始圖片的展示,達(dá)到動(dòng)畫(huà)的效果;
先新建一個(gè)CAShapeLayer,并設(shè)置為layer的遮罩;
新建一個(gè)動(dòng)畫(huà),設(shè)定初始和結(jié)束狀態(tài)并賦值給CAShapeLayer,完成一個(gè)遮罩動(dòng)畫(huà)。

    UIBezierPath *maskStartPath = [UIBezierPath bezierPathWithRect:CGRectMake(CGRectGetWidth(rainbowView1.bounds), 0, CGRectGetWidth(rainbowView1.bounds), CGRectGetHeight(rainbowView1.bounds))];
    UIBezierPath *maskFinalPath = [UIBezierPath bezierPathWithRect:rainbowView1.bounds];
    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    rainbowView1.layer.mask = maskLayer;
    maskLayer.path = maskFinalPath.CGPath;
    CABasicAnimation *maskLayerAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
    maskLayerAnimation.fromValue = (__bridge id)maskStartPath.CGPath;
    maskLayerAnimation.toValue = (__bridge id)maskFinalPath.CGPath;
    maskLayerAnimation.removedOnCompletion = NO;
    maskLayerAnimation.duration = 2.0;
    maskLayerAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [maskLayer addAnimation:maskLayerAnimation forKey:@"maskLayerAnimation"];

7、旋轉(zhuǎn)效果

燈光掃動(dòng),花朵旋轉(zhuǎn)等旋轉(zhuǎn)效果,都可以transform的rotation.z屬性來(lái)實(shí)現(xiàn);
同樣使用CAKeyframeAnimation實(shí)現(xiàn),設(shè)定好初始、中間、結(jié)束狀態(tài),動(dòng)畫(huà)時(shí)間已經(jīng)重復(fù)次數(shù),并添加到layer,完成旋轉(zhuǎn)效果;

    CAKeyframeAnimation* rotationAnimation;
    rotationAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.values = @[@(M_PI / 12), @(M_PI / 3), @(M_PI / 12)];
    rotationAnimation.duration = 2.5;
    rotationAnimation.fillMode = kCAFillModeBoth;
    rotationAnimation.calculationMode = kCAAnimationCubic;
    //    rotationAnimation.cumulative = YES;
    rotationAnimation.repeatCount = HUGE_VALF;
    
    [self.mLightLeftView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];

8、幀動(dòng)畫(huà)

某些復(fù)雜動(dòng)畫(huà)不是靠對(duì)原始圖像操作進(jìn)行操作就能實(shí)現(xiàn),這時(shí)候就要用到幀動(dòng)畫(huà)
幀動(dòng)畫(huà)有兩種實(shí)現(xiàn)方式,一種是通過(guò)Timer(定時(shí)器),設(shè)定好時(shí)間間隔,手動(dòng)替換圖片;
另外一種是通過(guò)UIImageView的支持,實(shí)現(xiàn)幀動(dòng)畫(huà)。

UIImageView的幀動(dòng)畫(huà)沒(méi)有回調(diào),如果需要實(shí)現(xiàn)達(dá)到第幾幀之后,開(kāi)始另外的動(dòng)畫(huà)的效果,需要用第一種方法。

    NSMutableArray<UIImage *> *images = [NSMutableArray<UIImage *> array];
    for (int i = 0; i < 6; ++i) {
        UIImage *img = [[AnimationImageCache shareInstance] getDriveImageWithName:[NSString stringWithFormat:@"gift_animation_angel_phoenix%d.png", i]];
        if (img) {
            [images addObject:img];
        }
    }
    self.mAngelPhoenixView.image = [[AnimationImageCache shareInstance] getDriveImageWithName:@"gift_animation_angel_phoenix0.png"];
    self.mAngelPhoenixView.animationImages = images;
    self.mAngelPhoenixView.animationDuration = 0.8;
    self.mAngelPhoenixView.animationRepeatCount = 1;
    [self.mAngelPhoenixView startAnimating];

動(dòng)畫(huà)的性能優(yōu)化

直播APP的性能優(yōu)化-禮物篇
iOS開(kāi)發(fā)-視圖渲染與性能優(yōu)化
都有,不再贅述。

總結(jié)

UIView的block動(dòng)畫(huà)中,completion持有的是強(qiáng)引用,需要避免造成循環(huán)引用。

但在調(diào)用完畢completion后,會(huì)釋放引用。

天使動(dòng)畫(huà)的圖片大小為900KB,運(yùn)行時(shí)占內(nèi)存15MB,播放完畢后,如果收到內(nèi)存不足的警告會(huì)釋放內(nèi)存;

煙花動(dòng)畫(huà)的圖片大小為400KB,運(yùn)行時(shí)占用的內(nèi)存為20MB,播放完畢后,會(huì)馬上釋放內(nèi)存;

思考題??
1、為什么煙花動(dòng)畫(huà)的圖片大小比較小,運(yùn)行時(shí)占用的內(nèi)存反而更多?

2、播放完畢馬上釋放和收到內(nèi)存不足警告再釋放,兩種圖片加載方式的優(yōu)缺點(diǎn)?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,530評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,407評(píng)論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,981評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,759評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,204評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,415評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,955評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,650評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,892評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,675評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評(píng)論 2 374

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

  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫(huà)全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,543評(píng)論 6 30
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺iOS動(dòng)畫(huà)全貌。在這里你可以看...
    F麥子閱讀 5,131評(píng)論 5 13
  • 在iOS實(shí)際開(kāi)發(fā)中常用的動(dòng)畫(huà)無(wú)非是以下四種:UIView動(dòng)畫(huà),核心動(dòng)畫(huà),幀動(dòng)畫(huà),自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。 1.UIView...
    請(qǐng)叫我周小帥閱讀 3,128評(píng)論 1 23
  • 3月12日,我的一天之我終于會(huì)跳牛仔套路了。 今天上拉丁課的時(shí)候,老師們用了一整節(jié)課的時(shí)候時(shí)間教會(huì)了我們這些不會(huì)拉...
    Sernedipity閱讀 217評(píng)論 1 0
  • 以前看過(guò)一段話(huà) 是這樣的 “聽(tīng)過(guò)很多場(chǎng)開(kāi)端氣派 結(jié)尾草草的感情 都是在一場(chǎng)又一場(chǎng) 彼此為自尊較勁的爭(zhēng)吵里相互消耗掉...
    ae142234e286閱讀 291評(píng)論 0 0