iOS分類--電商類等項目中商品圖片加入購物車動畫效果(將敬業(yè)福加入購物車)

下面給大家說一個將敬業(yè)福加入購物車的方法

在項目過程中所涉及到的一個需求,效果和天貓京東等的那種控制器下沉,然后具體商品型號類型等的展示view彈出,加入購物車時圖片的動畫效果差不多,經(jīng)過一些研究查閱之后做了一個非常標準的實現(xiàn),并且在此基礎(chǔ)上做了稍稍一些擴展.大體效果如下:

record01.gif
record03.gif
record04.gif

實現(xiàn)方式是通過 UIImageView + Category 的方式實現(xiàn)的,用分類的方式來實現(xiàn)不會對原有類產(chǎn)生任何影響.

動畫過程是以UIBezierPath, CABasicAnimation及其子類CAKeyframeAnimation等來實現(xiàn)的,并且通過運行時 runtime 的特性為分類增加了一些屬性,更加方便我們?nèi)フ{(diào)用設(shè)置.大體想法是通過貝塞爾路徑畫出圖片所要做的位移路徑,并且在圖片做位移動畫的過程中,通過CABasicAnimation核心動畫的控制,讓圖片的旋轉(zhuǎn),縮放,拋物線,移動速率等的動畫同時發(fā)生.

已經(jīng)寫過一篇文章講述了控制器的3D下沉上升效果,這里就不多說了.主要分析下圖片動畫的過程.整個圖片的位移路徑首先是通過貝塞爾路徑來控制的,先說一下簡單的一個中心控制點的路徑,大多數(shù)電商APP圖片的移動路徑也都是這種的:

    UIBezierPath *path = [UIBezierPath bezierPath];
    CGPoint startPoint = [self convertPoint:self.center toView:nil];
    CGPoint endPoint = [[[self endPointAndHadianHeightByTransformEndType:transformType] firstObject] CGPointValue];
簡單方式: 為路徑設(shè)置一個中心控制點(拋物線單頂點):######
    CGFloat radianHeight = [[[self endPointAndHadianHeightByTransformEndType:transformType] lastObject] floatValue];
    
    float sx = startPoint.x,    sy = startPoint.y,  ex = endPoint.x,    ey = endPoint.y;
    float x = sx + (ex - sx)/3,  y = sy + (ey - sy)*0.5 - radianHeight;
    CGPoint centerPoint=CGPointMake(x,y);

然后將起始點和中心點都加入貝塞爾路徑中,同時調(diào)用自定義的CAAnimation核心動畫方法:

    [path moveToPoint:startPoint];
    [path addQuadCurveToPoint:endPoint controlPoint:centerPoint];
    
    [self transformWithBezierPath:path duration:duration];
兩個控制點的方式: 為路徑設(shè)置兩個控制點(一上一下兩個頂點):######
    CGFloat radianHeight = [[[self endPointAndHadianHeightByTransformEndType:transformType] lastObject] floatValue];
    
    CGPoint controlPoint1 = [[[self controlPointsByParabolaType:parabolaType startPoint:startPoint endPoint:endPoint radianHeight:radianHeight] firstObject] CGPointValue];
    CGPoint controlPoint2 = [[[self controlPointsByParabolaType:parabolaType startPoint:startPoint endPoint:endPoint radianHeight:radianHeight] lastObject] CGPointValue];

    [path moveToPoint:startPoint];
    [path addCurveToPoint:endPoint controlPoint1:controlPoint1 controlPoint2:controlPoint2];

自定義的CAAnimation核心動畫方法- (void)transformWithBezierPath:(UIBezierPath *)path duration:(NSTimeInterval)duration;內(nèi),

首先要確定一件事:該部分執(zhí)行動畫的圖層全部都以 keyWindow 為參考系進行的,并且要為圖層新建一個layer對象作為執(zhí)行動畫的圖層,讓圖片在新的layer上進行位移,不然會直接作用于原圖片.
然后在此基礎(chǔ)上實現(xiàn)三個動畫:圖層的拋物線,圖層的旋轉(zhuǎn)和圖層的尺寸縮放:

- (void)transformWithBezierPath:(UIBezierPath *)path duration:(NSTimeInterval)duration{
    
    //該部分動畫的imageview 全部都以  keyWindow  為參考系進行
    UIWindow *window = [UIApplication sharedApplication].keyWindow;

    CGRect rect = [self convertRect:self.bounds toView:window];
    
    CALayer *layer = [[CALayer alloc] init];
    layer.contents = self.layer.contents;
    layer.frame = rect;
    layer.opacity = 1;
    [window.layer addSublayer:layer];

    //拋物線
    CAKeyframeAnimation *parabolaPathAnimation=[CAKeyframeAnimation animationWithKeyPath:@"position"];
    parabolaPathAnimation.path = path.CGPath;   //pao
    parabolaPathAnimation.autoreverses = NO;  //自動復(fù)位為NO
    parabolaPathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    parabolaPathAnimation.duration = duration;
    parabolaPathAnimation.fillMode = kCAFillModeForwards; //動畫狀態(tài)是否保持
    parabolaPathAnimation.removedOnCompletion = NO;    //完成后移除
    
    //旋轉(zhuǎn)
    CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 8];
    rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    rotationAnimation.cumulative = YES;
    rotationAnimation.duration = duration;
    rotationAnimation.fillMode = kCAFillModeForwards;
    rotationAnimation.removedOnCompletion = NO;
    
    
    //尺寸縮放
    CAKeyframeAnimation *transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    CATransform3D scale1 = CATransform3DMakeScale(1.0, 1.0, 1),
    scale2 = CATransform3DMakeScale(0.65, 0.65, 1),
    scale3 = CATransform3DMakeScale(0.2, 0.2, 1),
    scale4 = CATransform3DMakeScale(.0, .0, 1);
    NSArray *frameValues = [NSArray arrayWithObjects:
                            [NSValue valueWithCATransform3D:scale1],
                            [NSValue valueWithCATransform3D:scale2],
                            [NSValue valueWithCATransform3D:scale3],
                            [NSValue valueWithCATransform3D:scale4], nil];
    [transformAnimation setValues:frameValues];
    //兩種速率控制方式均可
    NSArray *frameTimes = [NSArray arrayWithObjects:@0,@0.5,@0.8,@1,nil];
    [transformAnimation setKeyTimes:frameTimes];
    //    transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    transformAnimation.duration = duration;
    transformAnimation.fillMode = kCAFillModeForwards;
    transformAnimation.removedOnCompletion = NO;
    
    
    [layer addAnimation:parabolaPathAnimation forKey:@"parabolaPathAnimation"];
    [layer addAnimation:transformAnimation forKey:@"transformAnimation"];
    [layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}

分類里具體提供了三個方法供大家來調(diào)用:

/**
 *  圖片做貝塞爾路徑的形變位移便捷方法
 *
 *  @param transformType 位移的結(jié)束點類型
 */
- (void)animationWithBezierPathTransformEndType:(TransformEndType)transformType duration:(NSTimeInterval)duration;

/**
 *  圖片做多控制點貝塞爾路徑的形變位移標準方法
 *
 *  @param parabolaType 貝塞爾拋物線類型
 *  @param view         目標view
 */
- (void)animationWithBezierPathTransformParabolaType:(ParabolaType)parabolaType toView:(UIView *)view duration:(NSTimeInterval)duration;

/**
 *  圖片做多控制點貝塞爾路徑的形變位移擴展方法
 *
 *  @param transformType 位移的結(jié)束點類型
 *  @param parabolaType  貝塞爾拋物線類型
 */
- (void)animationWithTwoControlPointsBezierPathTransformEndType:(TransformEndType)transformType parabolaType:(ParabolaType)parabolaType duration:(NSTimeInterval)duration;

便捷方法只需要傳入動畫時間duration以及

/** 位移的結(jié)束點類型 */
typedef NS_ENUM(NSInteger, TransformEndType) {
    /** 結(jié)束點 : 導(dǎo)航條的右上角 */
    TypeNavRightItemPoint = 0,
    /** 結(jié)束點 : Tabbar的第3個(從0開始) */
    TypeTabBarIndex3Point = 1,
    /** 結(jié)束點 : 與選中圖片對稱 */
    TypeSymmetricWithImage = 2,
    /** 結(jié)束點 : 自定義結(jié)束點,需要設(shè)提前置endPoint與radianHeight */
    TypeCustomPoint = 3,
};

的枚舉值,通常情況下直接選定比如TypeNavRightItemPoint就好;

標準方法需要傳入我們的位移目標位置出的小視圖,比如導(dǎo)航條的右側(cè)按鈕,tabbar的第幾個按鈕等,因為一旦選用控制器3D下沉效果的話,導(dǎo)航條的右側(cè)按鈕相對于keyWindow的位置是會改變的,如果繼續(xù)選擇第一個方法,最終的位置會出現(xiàn)偏差:

record06.gif

看到?jīng)],敬業(yè)福我們可以直接購買了

換上標準方法就好了,傳入目標view:

//        [self.goodImage animationWithBezierPathTransformEndType:TypeNavRightItemPoint duration:duration];
        
        UIView *view = self.currentVc.navigationItem.rightBarButtonItem.customView;
        [self.goodImage animationWithBezierPathTransformParabolaType:ParabolaTypeUp toView:view duration:duration];

可以看到不管控制器有沒有下沉,導(dǎo)航條右按鈕相對window的frame跑到哪里,都可以準確地定位到其中:

record07.gif

擴展方法主要是多了一個```/** 貝塞爾拋物線類型 /
typedef NS_ENUM(NSInteger, ParabolaType) {
/
* 上頂點 /
ParabolaTypeUp = 0,
/
* 先下后上 /
ParabolaTypeDownAndUp = 1,
/
* 先上后下 */
ParabolaTypeUpAndDown = 2,
};

[self.goodImage animationWithTwoControlPointsBezierPathTransformEndType:TypeNavRightItemPoint parabolaType:ParabolaTypeDownAndUp duration:duration];

最終效果:

![record08.gif](http://upload-images.jianshu.io/upload_images/1717878-e81e79010f3ca5e6.gif?imageMogr2/auto-orient/strip)


這里也做了一份完整的demo,放在了github上,大家可以去看一下:[傳送門](https://github.com/coderlinxx/XXBezierTransform) ,如果能幫助到您或有興趣,幫忙點個贊就更好了,謝謝?

Ps:gif軟件做出來的圖片動畫效果都不太順暢,dome里做出的效果都是挺順滑的,去下一個看看就好了。另外哪位兄弟給推薦一個比較好的錄制gif圖片的軟件。。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,688評論 6 30
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,268評論 5 13
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,962評論 25 709
  • 概覽 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌。在這里你...
    被吹落的風(fēng)閱讀 1,703評論 1 2
  • 還是
    悲傷的味道閱讀 106評論 0 0

友情鏈接更多精彩內(nèi)容