你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> 一句代碼添加新浪彈出框動畫

一句代碼添加新浪彈出框動畫

編輯:關於IOS
[收起] 文章目錄
  • 一、背景的毛玻璃效果
  • 二、彈性動畫
  • 三、動畫進行時對用戶交互的處理
  • 總結:

新浪微博中的“加號按鈕”點擊後的彈出動畫很有意思,每當一個人孤單寂寞冷的時候總會不停的點這個動畫,終於忍不住自己撸了一個。廢話不多說,直接上效果圖: 一句代碼添加新浪彈出框動畫

首先說一下通過這個動畫制作過程給大家分享的技術問題: 1.背景的毛玻璃效果 2.彈性動畫 3.動畫進行時對用戶交互的處理 4.UIControlevent 類型

一、背景的毛玻璃效果

對新浪微博中彈出動畫背景的思路分析:

新浪的背景動畫效果是有一個透明漸變的過程,並且最終漸變停止之後顯示的是一個帶有毛玻璃(半透明模糊)效果的視圖。我的模仿思路是當准備要彈出動畫的時候對整個視圖進行截屏操作,將截屏後的圖片進行毛玻璃效果渲染,然後在視圖上加一個背景 UIImageView 來顯示這張圖片,然後通過 alpha 動畫來由透明逐漸漸變出來。

1.對視圖進行截屏:

    UIGraphics BeginImageContextWithOptions(size, NO, scale);
    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage * image = UIGraphicsGetImageFromCurrentImageContext();

2.截屏後加上毛玻璃效果:

制作毛玻璃效果有三種選擇,一是 iOS8 後推出的 UIBlurEffectUIVisualEffectView 來直接顯示一個帶有毛玻璃效果的 View 不過這種方式並不能直接生成一張帶有毛玻璃效果的圖片,而且它的模糊程度設置方法非常有限只有那幾個枚舉類型,無法滿足需求。

第二種是通過 CoreImage 添加濾鏡的方式來實現毛玻璃效果,不過這種方式有個缺點如果濾鏡使用頻繁會對主線程產生影響,如果我不斷頻繁的重復動畫效果就必須要做判斷看濾鏡是否正在起作用,否則會經常出現崩潰和內存洩漏問題。

第三種我們使用蘋果13年 WWDC 上發布的官方 sample 一個 UIImage 的分類 UIImage+ImageEffects.h ,它不但可以制作毛玻璃效果圖片,而且可以調整模糊程度和顏色渲染。下面給出代碼:

    image = [image bhb_applyBlurWithRadius:15 
                                 tintColor:tintColor 
                     saturationDeltaFactor:1 
                                 maskImage:nil];//因為OC沒有命名空間,避免你的程序中使用到了這個分類導致沖突,我加了前綴

最終的顯示效果很不錯,我將模糊程度盡量的調節到與新浪微博一致了,不過在這個過程中,我發現當我頻繁的進行彈出操作時,內存會不斷攀升如下圖: 一句代碼添加新浪彈出框動畫 內存暴增的原因肯定是因為剛才的截圖或者毛玻璃效果導致的,我們來用 InstrumentsAllocations 來進行內存分析,找出元凶。 Xcode -> Product -> Profile -> Allocations, 開啟之後我們來使用右下角的 Mark generation(內存快照功能,進一步了解請移步[這片文章][1]) 一句代碼添加新浪彈出框動畫 在彈出 View 和移除 View的兩個時間點加 Mark generation一句代碼添加新浪彈出框動畫可以觀察到,兩個時間點竟然相差了4.31M,這是一個相當恐怖的數字,怪不得我點擊幾次彈出功能之後內存會暴增,讓我們繼續跟蹤: 一句代碼添加新浪彈出框動畫一句代碼添加新浪彈出框動畫 一句代碼添加新浪彈出框動畫跟蹤到最後,我們發現大部分未釋放的內存來自於繪圖和位圖的創建,回想我們當初做的截圖操作,圖片上下文開啟後並沒有進行關閉操作,所以在程序不斷截圖的過程中開啟了無數的圖片上下文而且不會被釋放,添加下面這句關鍵的代碼就可以解決問題(NC的我竟然連這個都忘了加-.-):

        UIGraphicsEndImageContext();

二、彈性動畫

新浪動畫中,按鈕彈出的動畫為彈性效果,按鈕到達最終位置後不會直接停止,而是做類似彈簧的一種阻尼運動,要實現這種動畫也很簡單 iOS7 後蘋果非常給力的添加了 spring 彈性動畫的快速創建方式:

    [UIView animateWithDuration:(NSTimeInterval) 
                          delay:(NSTimeInterval) 
         usingSpringWithDamping:(CGFloat) 
          initialSpringVelocity:(CGFloat) 
                        options:(UIViewAnimationOptions) 
                     animations:^{} 
                     completion:^(BOOL finished) {}];

通過對 Damping 阻力和 Velocity 初速度的設置可以實現彈性動畫動畫效果如下圖: 一句代碼添加新浪彈出框動畫

當然實現彈性動畫還可以使用[Jonathan Willing][2]大大的 JNWSpringAnimation ,你可以像使用 CABasicAnimation 一樣輕松的使用它,通過改變關鍵的3個屬性 Damping 阻力, stiffness 硬直, mass 質量來改變彈性動畫的效果代碼如下:

   JNWSpringAnimation *scale = [JNWSpringAnimation
    animationWithKeyPath:@"transform.translation.x"];
    scale.damping = 7;
    scale.stiffness = 7;
    scale.mass = 1;

    scale.fromValue = @(0);
    scale.toValue = @(400);

    [redBall.layer addAnimation:scale forKey:scale.keyPath];
    redBall.transform = CGAffineTransformMakeTranslation(400, 0);

關鍵的三個屬性對動畫的影響如下圖: 一句代碼添加新浪彈出框動畫

為了減輕項目對第三方框架的依賴,我使用了 iOS7 原生的 spring 動畫,如果你想要兼容以前版本,替換成 JNWSpringAnimation 即可。回到新浪動畫的制作,動畫是6個按鈕按照順序依次出現和消失,並且點擊 more 按鈕後可以向左平移到第二屏幕,並且在第二屏幕點擊 叉號 按鈕動畫會加在第二屏幕的6個按鈕上。 效果如圖: 一句代碼添加新浪彈出框動畫

對此我使用了一個 UIScrollView 來承載這些按鈕,並聲明2個數組用來保存所有的按鈕和正在顯示的按鈕(在屏幕上,並且需要做動畫):

    @property (nonatomic,strong) NSMutableArray * visableArray;//屏幕顯示的按鈕數組
    @property (nonatomic,strong) NSMutableArray * itemsArray;//所有按鈕的數組

這樣我在給這些按鈕加動畫的時候就不會浪費性能,只把動畫加在當前顯示在屏幕的按鈕上。動畫依次按照一定的時間差來執行,解決的辦法我是用的 GCD :

    [self.visableArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        BHBCustomBtn * btn = obj;
        CGFloat x = btn.frame.origin.x;
        CGFloat y = btn.frame.origin.y;
        CGFloat width = btn.frame.size.width;
        CGFloat height = btn.frame.size.height;
        btn.frame = CGRectMake(x, [UIScreen mainScreen].bounds.size.height + y - self.frame.origin.y, width, height);
        btn.alpha = 0.0;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(idx * 0.03 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [UIView animateWithDuration:0.35 delay:0 usingSpringWithDamping:0.85 initialSpringVelocity:25 options:UIViewAnimationOptionCurveEaseIn animations:^{
                btn.alpha = 1;
                btn.frame = CGRectMake(x, y, width, height);
            } completion:^(BOOL finished) {
                if ([btn isEqual:[self.visableArray lastObject]]) {
                    self.superview.superview.userInteractionEnabled = YES;
                }
            }];
        });
    }];

這樣按鈕就會依次以彈性動畫的形式彈動出來了,是不是很簡單,對於動畫結束後所作的處理我將在下一節中說明。

三、動畫進行時對用戶交互的處理

動畫過程中,處理用戶交互的問題相當關鍵,視圖動畫中默認自動停止響應用戶交互,因此當按鈕進行彈性動畫時,觸摸它並不會生成任何事件。 但是當你觸摸加號按鈕的時候,會再次進行彈出框動畫,這時就會彈出兩個彈出框,這是我們不希望看到的,我們可以將加號按鈕的 enable屬性設置為 YES 但是這樣做我們要在封裝的視圖內部獲取外部的加號按鈕,這一點違背了封裝性原則,並不是一個好的設計。所以我在所有按鈕的彈性動畫開始時,設置:

    self.superview.superview.userInteractionEnabled = NO;

注意視圖的層級關系,我所設計的 BHBPopView 內部裝著一個 UIScrollView,而它上面放著這些按鈕,所以你要找到父視圖的父視圖才能夠統一屏蔽用戶的交互行為,當所有的按鈕彈性動畫結束時,也就是 visableArray 數組最後一個按鈕動畫結束時,我們恢復用戶的交互:

    self.superview.superview.userInteractionEnabled = YES;

這樣當動畫進行過程中,屏蔽了用戶的交互,避免發生一些意外的情況。

四、UIControlevent 類型

注意到新浪動畫裡面按鈕有一個放大效果,並且當你手指放上去的時候放大,手指稍微挪動,便恢復原始大小。讓我們先來看一下動畫:

一句代碼添加新浪彈出框動畫

要實現這個效果只需要做一個形變動畫就可以了,關鍵是我們如何控制它放大和恢復大小。 思路如下:按鈕是繼承自 UIControlUIControl 有不同的事件狀態:

    UIControlEventTouchDown           = 1 <<  0,      // 手指落在按鈕的一瞬間觸發
    UIControlEventTouchDownRepeat     = 1 <<  1,      // 多點觸碰的時候,當第二根以上的手指觸摸瞬間出發
    UIControlEventTouchDragInside     = 1 <<  2,      // 手指在視圖范圍內拖動觸發
    UIControlEventTouchDragOutside    = 1 <<  3,      // 手指在視圖范圍外拖動觸發
    UIControlEventTouchDragEnter      = 1 <<  4,      // 手指從視圖外拖動到視圖內時觸發
    UIControlEventTouchDragExit       = 1 <<  5,      // 手指從視圖內部拖動到視圖外時觸發
    UIControlEventTouchUpInside       = 1 <<  6,      // 手指在視圖內部抬起時觸發
    UIControlEventTouchUpOutside      = 1 <<  7,      // 手指在視圖外部抬起時觸發
    UIControlEventTouchCancel         = 1 <<  8,      // 取消事件,放上了太多手指或者被上鎖或者電話呼叫打斷。

    UIControlEventValueChanged        = 1 << 12,      // 當視圖的值發生改變時,發送通知。

    UIControlEventEditingDidBegin     = 1 << 16,     // UITextField
    UIControlEventEditingChanged      = 1 << 17,
    UIControlEventEditingDidEnd       = 1 << 18,
    UIControlEventEditingDidEndOnExit = 1 << 19,     // 'return key' ending editing

    UIControlEventAllTouchEvents      = 0x00000FFF,  // for touch events
    UIControlEventAllEditingEvents    = 0x000F0000,  // for UITextField
    UIControlEventApplicationReserved = 0x0F000000,  // range available for application use
    UIControlEventSystemReserved      = 0xF0000000,  // range reserved for internal framework use
    UIControlEventAllEvents           = 0xFFFFFFFF

我們所用到的事件是 TouchDownDragInside,手指放上去觸發 TouchDown 放大視圖,在視圖內部移動 DragInside 時恢復視圖,注意按鈕的作用范圍是整個矩形區域包含了圖片和文字,當你的手指移出圖片的時候並非一定會移出按鈕作用范圍,所以依然會觸發 TouchUpInsite 事件,這時候我們需要做一個屬性來記錄用戶拖拽之後取消按鈕的 TouchUpInsite 執行。

    @property (nonatomic,assign) BOOL btnCanceled;

這樣我們就可以實現動畫效果了,具體代碼如下:

    //處理按鈕有效的點擊事件,當前按鈕放大消失,其他按鈕縮小消失,回調點擊事件
    [btn addTarget:self action:@selector(didClickBtn:) forControlEvents:UIControlEventTouchUpInside];
    //處理手指按下事件,放大按鈕
    [btn addTarget:self action:@selector(didTouchBtn:) forControlEvents:UIControlEventTouchDown];
    //處理手指拖動事件,恢復按鈕大小
    [btn addTarget:self action:@selector(didCancelBtn:) forControlEvents:UIControlEventTouchDragInside];

總結:

制作類似新浪微博這種彈出框動畫,我的思路是先分析邏輯,這些特效都由哪些組成,毛玻璃背景,加頂部一個 logo ,加中間 UIScrollView和上面的很多按鈕,加底部工具條。研究透徹動畫的執行順序,動畫執行結果有哪些分支。然後針對特效中的難點,比如毛玻璃,按鈕彈性動畫等等進行逐一研究攻破,最後將這些組件整合在一起變成一個好玩的動畫,最後不要忘了動畫的內存和性能測試。這次我模仿的新浪微博動畫彈性效果並不是太理想,比起新浪原生來說不是特別一致,也希望有興趣的你來給我一些建議優化它。最終在你的項目中加入我的彈出框動畫真的只需要一句話哦:

    /**
    *  直接顯示一個popView在某個view上
    *
    *  @param view       父view
    *  @param imageArray 圖標數組
    *  @param titles     標題數組
    *  @param block      回調
    *  @return pop視圖
    */
    + (BHB_INSTANCETYPE)showToView:(UIView *)view andImages:(NSArray *)imageArray andTitles:(NSArray *)titles andSelectBlock:(DidSelectItemBlock)block;
    /**
    *  如果顯示一個帶more功能的,請使用此方法
    *
    *  @param view  父view
    *  @param array BHBItem類型的集合
    *  @param block 回調
    *  @return pop視圖
    */
    + (BHB_INSTANCETYPE)showToView:(UIView *)view withItems:(NSArray *)array andSelectBlock:(DidSelectItemBlock)block;

hexo出點問題修復到下半夜啊(升級到3.0太蛋疼了),現在腦子暈暈的,明天還要去新公司入職,動畫中還有很多細節我不能一一分享了,歡迎大家來搞我的Demo

good luck!

原文鏈接:http://bihongbo.com/2015/08/19/sinaAnimation/

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved