場景:直播間刷禮物時(shí),會從發(fā)送按鈕處飄一個(gè)選中的禮物到主播的頭像處涝缝。
原理:找到發(fā)送按鈕和主播頭像所在它們共同的父視圖的位置,然后進(jìn)行組合動畫操作
實(shí)現(xiàn)一個(gè)類烦衣,來完成這個(gè)功能
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface GiftAnimation : NSObject
//這個(gè)的gift可以作為外部送禮物的URL進(jìn)行展示,userID可以作為唯一標(biāo)識來處理特殊業(yè)務(wù)邏輯
+ (void)animationGiftWithFromRect:(CGRect)from startPoint:(CGPoint)startPoint toRect:(CGRect)to giftBean:(NSString *)gift micUser:(NSInteger)userID superView:(nonnull UIView *)aView;
@end
NS_ASSUME_NONNULL_END
#import "GiftAnimation.h"
@implementation GiftAnimation
+ (void)animationGiftWithFromRect:(CGRect)from startPoint:(CGPoint)startPoint toRect:(CGRect)to giftBean:(NSString *)gift micUser:(NSInteger)userID superView:(nonnull UIView *)aView{
if (to.size.width == 0) {
return;
}
UIImageView * contentView = [UIImageView new];
contentView.frame = from;
//可以使用傳過來的入?yún)⑦M(jìn)行網(wǎng)絡(luò)圖片加載摘投,暫時(shí)用本地演示
contentView.image = IMAGE(@"gift");
//業(yè)務(wù)邏輯中可以使用userID作為唯一標(biāo)識
contentView.tag = userID;
CGPoint endPoitnt = CGPointMake(to.origin.x+ to.size.width/2, to.origin.y + to.size.height/2);
CGFloat height = startPoint.y - endPoitnt.y;
CGFloat width = startPoint.x - endPoitnt.x;
CGPoint ceterPoint1 = CGPointMake(startPoint.x - width/2, startPoint.y - height /3);
CGPoint ceterPoint2 = CGPointMake(startPoint.x - 2*width/3, startPoint.y - 2*height /3);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:startPoint]; // 起點(diǎn)
// 設(shè)置終點(diǎn) 和兩個(gè)控制點(diǎn)(拐點(diǎn))
[path addCurveToPoint:endPoitnt controlPoint1:ceterPoint1 controlPoint2:ceterPoint2];
//第二步:創(chuàng)建關(guān)鍵幀動畫
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//pathAnimation.calculationMode = kCAAnimationPaced;// 我理解為節(jié)奏
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;// 是否在動畫完成后從 Layer 層上移除 回到最開始狀態(tài)
pathAnimation.duration = 1.0f;// 動畫時(shí)間
pathAnimation.delegate = (id)aView;
pathAnimation.repeatCount = 1;// 動畫重復(fù)次數(shù)```
pathAnimation.path = path.CGPath;
///第三步:透明動畫
CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
opacityAnim.toValue = [NSNumber numberWithFloat:0.0];
opacityAnim.beginTime = 1.0;
opacityAnim.duration = 2.0;
opacityAnim.removedOnCompletion = NO;
opacityAnim.fillMode = kCAFillModeForwards;
//動畫組
CAAnimationGroup *animGroup = [CAAnimationGroup animation];
animGroup.animations = [NSArray arrayWithObjects:pathAnimation, opacityAnim, nil];
animGroup.duration = 3.0;
animGroup.delegate = (id)aView;
animGroup.fillMode = kCAFillModeForwards;
animGroup.removedOnCompletion = NO;
//第四步: 添加動畫
[contentView.layer addAnimation:animGroup forKey:[NSString stringWithFormat:@"myAnimation"]];// 添加動畫
[aView addSubview:contentView];
//防止UIImage只生成不銷毀妄帘,占用內(nèi)存唆鸡,動畫完實(shí)時(shí)銷毀
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[contentView removeFromSuperview];
});
}
@end
外部使用:
例子:一個(gè)發(fā)送按鈕fromBtn,點(diǎn)擊fromBtn脑慧,會從fromBtn處飄一個(gè)禮物到頭像toIcon處
//獲取fromBtn所在父視圖的坐標(biāo)位置CGRect
CGRect fromRec = [self.fromBtn convertRect:self.fromBtn.bounds toView:self.view];
//獲取禮物初始位置魄眉,即fromBtn的中心點(diǎn)位置
CGPoint point = CGPointMake(fromRec.origin.x + (fromRec.size.width/2), fromRec.origin.y + (fromRec.size.height/2));
//獲取toIcon所在父視圖的坐標(biāo)位置CGRect
CGRect toRec = [self.toIcon convertRect:self.toIcon.bounds toView:self.view];
//調(diào)用方法,開始動畫闷袒,micUser和giftBean可以根據(jù)具體業(yè)務(wù)具體處理坑律,不需要的可以去除
[GiftAnimation animationGiftWithFromRect:rec startPoint:point toRect:toRec giftBean:@"" micUser:32 superView:self.view];