1. 廣播跑馬燈html
2. 彈幕動畫dom
3. 直播點贊動畫ide
4. 直播點贊圖片動畫測試
5. 煙花動畫動畫
6. 雪花動畫atom
1. 廣播動畫特效:spa
思路:代理
1. 初始化廣播視圖orm
2. 設置廣播公告廣告內容htm
3. 添加動畫效果
初始化廣播視圖, 廣播活動標題按鈕 與 廣播活動標題標籤 控件大小同樣
/** * 設置廣播視圖 */ - (void)setupBroadcastingView { // 設置廣播活動標題按鈕 UIButton *activityBtn = [UIButton buttonWithType:UIButtonTypeCustom]; activityBtn.frame = CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, 30); activityBtn.backgroundColor = [UIColor clearColor]; [activityBtn addTarget:self action:@selector(activityDetail) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:activityBtn]; self.activityBtn = activityBtn; // 設置廣播活動標題文字 UILabel *activityLb = [[UILabel alloc] init]; activityLb.frame = activityBtn.bounds; [activityLb setFont:[UIFont boldSystemFontOfSize:14]]; [activityLb setTextColor:[UIColor colorWithRed:115/255.0 green:125/255.0 blue:134/255.0 alpha:1.0]]; [activityLb setBackgroundColor:[UIColor clearColor]]; [activityBtn addSubview:activityLb]; self.activityLb = activityLb; // 設置廣播logo UIImageView *speaker = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"broadcasting"]]]; speaker.frame = CGRectMake(0, 5, 20, 20); speaker.backgroundColor = self.view.backgroundColor; [activityBtn addSubview:speaker]; // 設置廣播公告廣告內容 [self setActivityButtonTitle]; }
設置廣播公告廣告內容, 這裏是以假數據填充,通常需求會是後臺請求得來的活動內容.
添加動畫效果: 當文字內容超過顯示區域就滾動展現,未超過則居中展現.
/** * 設置廣播公告廣告內容 */ - (void)setActivityButtonTitle { // 廣播公告廣告內容(假數據) NSString *title = @"廣播公告廣告內容(ZL測試內容)廣播公告廣告內容(測試內容)\r\n廣播公告廣告內容(測試內容)廣播公告廣告內容(測試內容)廣播公告廣告內容(測試內容)"; title = [title stringByReplacingOccurrencesOfString:@"\r\n" withString:@" "]; [self.activityLb setText:title]; [self.activityLb sizeToFit]; if (self.activityLb.frame.size.width <= self.activityBtn.frame.size.width) { [self.activityLb setCenter:CGPointMake(self.activityBtn.frame.size.width/2, self.activityBtn.frame.size.height/2)]; } else { // 當文字內容超過顯示區域就滾動展現 CGRect frame = self.activityLb.frame; frame.origin.x = self.activityBtn.frame.size.width; frame.origin.y = self.activityBtn.frame.size.height * 0.5 - self.activityLb.bounds.size.height * 0.5; self.activityLb.frame = frame; [UIView beginAnimations:@"testAnimation" context:NULL]; [UIView setAnimationDuration:frame.size.width/55.f]; [UIView setAnimationCurve:UIViewAnimationCurveLinear]; [UIView setAnimationRepeatAutoreverses:NO]; [UIView setAnimationRepeatCount:INT_MAX]; frame = self.activityLb.frame; frame.origin.x = - frame.size.width; self.activityLb.frame = frame; [UIView commitAnimations]; } }
當有活動連接時,須要添加點擊效果; 若是沒則不須要建立按鈕及點擊效果.
// 展現活動詳情 - (void)activityDetail { NSLog(@"點擊了廣播活動公告詳情"); }
2. 彈幕動畫特效:
先自定義彈幕標籤ZLScrollLabelView:
.h 文件露出開始/中止/暫停/恢復彈幕動畫
@interface ZLScrollLabelView : UIView // 代理協議 @property (nonatomic, weak) id <ZLScrollLabelViewDelegate> delegate; // 速度 @property (nonatomic) CGFloat speed; // 方向 @property (nonatomic) ScrollDirectionType barrageDirection; // 容器 - (void)addContentView:(UIView *)view; // 開始 - (void)startAnimation; // 中止 - (void)stopAnimation; // 暫停 - (void)pauseAnimation; // 恢復 - (void)resumeAnimation; @end
.m 文件初始化:
- (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { _width = frame.size.width; _height = frame.size.height; self.speed = 1.f; self.barrageDirection = FromLeftType; self.layer.masksToBounds = YES; self.animationView = [[UIView alloc] initWithFrame:CGRectMake(_width, 0, _width, _height)]; [self addSubview:self.animationView]; } return self; } - (void)addContentView:(UIView *)view { [_contentView removeFromSuperview]; view.frame = view.bounds; _contentView = view; self.animationView.frame = view.bounds; [self.animationView addSubview:_contentView]; _animationViewWidth = self.animationView.frame.size.width; _animationViewHeight = self.animationView.frame.size.height; }
開始彈幕動畫:
- (void)startAnimation { [self.animationView.layer removeAnimationForKey:@"animationViewPosition"]; _stoped = NO; CGPoint pointRightCenter = CGPointMake(_width + _animationViewWidth / 2.f, _animationViewHeight / 2.f); CGPoint pointLeftCenter = CGPointMake(-_animationViewWidth / 2, _animationViewHeight / 2.f); CGPoint fromPoint = self.barrageDirection == FromLeftType ? pointRightCenter : pointLeftCenter; CGPoint toPoint = self.barrageDirection == FromLeftType ? pointLeftCenter : pointRightCenter; self.animationView.center = fromPoint; UIBezierPath *movePath = [UIBezierPath bezierPath]; [movePath moveToPoint:fromPoint]; [movePath addLineToPoint:toPoint]; CAKeyframeAnimation *moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; moveAnimation.path = movePath.CGPath; moveAnimation.removedOnCompletion = YES; moveAnimation.duration = _animationViewWidth / 30.f * (1 / self.speed); moveAnimation.delegate = self; [self.animationView.layer addAnimation:moveAnimation forKey:@"animationViewPosition"]; }
中止彈幕動畫:
- (void)stopAnimation { _stoped = YES; [self.animationView.layer removeAnimationForKey:@"animationViewPosition"]; } - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if (self.delegate && [self.delegate respondsToSelector:@selector(barrageView:animationDidStopFinished:)]) { [self.delegate barrageView:self animationDidStopFinished:flag]; } if (flag && !_stoped) { [self startAnimation]; } }
暫停彈幕動畫:
- (void)pauseAnimation { [self pauseLayer:self.animationView.layer]; } - (void)pauseLayer:(CALayer*)layer { CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil]; layer.speed = 0.0; layer.timeOffset = pausedTime; }
恢復彈幕動畫:
- (void)resumeAnimation { [self resumeLayer:self.animationView.layer]; } - (void)resumeLayer:(CALayer*)layer { CFTimeInterval pausedTime = layer.timeOffset; layer.speed = 1.0; layer.timeOffset = 0.0; layer.beginTime = 0.0; CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime; layer.beginTime = timeSincePause; }
在所需控制器裏, 添加代理ZLScrollLabelViewDelegate實現開始動畫方法
- (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title = @"彈幕動畫"; self.view.backgroundColor = [UIColor grayColor]; ZLScrollLabelView *barrageView0 = [[ZLScrollLabelView alloc] initWithFrame:CGRectMake(0, 104, self.view.frame.size.width, 20)]; barrageView0.delegate = self; // add [self.view addSubview:barrageView0]; // text [barrageView0 addContentView:[self createLabelWithText:@"超喜歡趙麗穎,只因她的踏實!" textColor:[self randomColor]]]; // start [barrageView0 startAnimation]; }
代理ZLScrollLabelViewDelegate:
- (UILabel *)createLabelWithText:(NSString *)text textColor:(UIColor *)textColor { NSString *string = [NSString stringWithFormat:@" %@ ", text]; CGFloat width = [string widthWithStringAttribute:@{NSFontAttributeName : [UIFont systemFontOfSize:14.f]}]; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width, 20)]; label.font = [UIFont systemFontOfSize:14.f]; label.text = string; label.textColor = textColor; return label; } #pragma mark - ZLScrollLabelViewDelegate - (void)barrageView:(ZLScrollLabelView *)barrageView animationDidStopFinished:(BOOL)finished { [barrageView stopAnimation]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [barrageView addContentView:[self createLabelWithText:[self randomString] textColor:[self randomColor]]]; [barrageView startAnimation]; }); } - (NSString *)randomString { NSArray *array = @[@"猜猜我是誰?", @"哈哈", @"猜不着吧", @"我是程序媛", @"嚕啦啦啦啦~"]; return array[arc4random() % array.count]; }
3. 直播點贊效果
先自定義ZLLiveHeartView,露出liveHeartAnimateInView方法:
- (void)liveHeartAnimateInView:(UIView *)view { NSTimeInterval totalAnimationDuration = 8; CGFloat heartSize = CGRectGetWidth(self.bounds); CGFloat heartCenterX = self.center.x; CGFloat viewHeight = CGRectGetHeight(view.bounds); // Pre-Animation setup self.transform = CGAffineTransformMakeScale(0, 0); self.alpha = 0; // Bloom [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.transform = CGAffineTransformIdentity; self.alpha = 0.9; } completion:NULL]; NSInteger i = arc4random_uniform(2); // -1 OR 1 NSInteger rotationDirection = 1 - (2 * i); NSInteger rotationFraction = arc4random_uniform(10); [UIView animateWithDuration:totalAnimationDuration animations:^{ self.transform = CGAffineTransformMakeRotation(rotationDirection * M_PI / (16 + rotationFraction * 0.2)); } completion:NULL]; UIBezierPath *heartTravelPath = [UIBezierPath bezierPath]; [heartTravelPath moveToPoint:self.center]; // random end point CGPoint endPoint = CGPointMake(heartCenterX + (rotationDirection) * arc4random_uniform(2 * heartSize), viewHeight/6.0 + arc4random_uniform(viewHeight / 4.0)); // random Control Points NSInteger j = arc4random_uniform(2); NSInteger travelDirection = 1- (2*j); // randomize x and y for control points CGFloat xDelta = (heartSize/2.0 + arc4random_uniform(2*heartSize)) * travelDirection; CGFloat yDelta = MAX(endPoint.y ,MAX(arc4random_uniform(8*heartSize), heartSize)); CGPoint controlPoint1 = CGPointMake(heartCenterX + xDelta, viewHeight - yDelta); CGPoint controlPoint2 = CGPointMake(heartCenterX - 2*xDelta, yDelta); [heartTravelPath addCurveToPoint:endPoint controlPoint1:controlPoint1 controlPoint2:controlPoint2]; CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; keyFrameAnimation.path = heartTravelPath.CGPath; keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; keyFrameAnimation.duration = totalAnimationDuration + endPoint.y/viewHeight; [self.layer addAnimation:keyFrameAnimation forKey:@"positionOnPath"]; // Alpha & remove from superview [UIView animateWithDuration:totalAnimationDuration animations:^{ self.alpha = 0.0; } completion:^(BOOL finished) { [self removeFromSuperview]; }]; }
- (void)drawRect:(CGRect)rect { [_strokeColor setStroke]; [_fillColor setFill]; CGFloat drawingPadding = 4.0; CGFloat curveRadius = floor((CGRectGetWidth(rect) - 2*drawingPadding) / 4.0); // Creat path UIBezierPath *heartPath = [UIBezierPath bezierPath]; // Start at bottom heart tip CGPoint tipLocation = CGPointMake(floor(CGRectGetWidth(rect) / 2.0), CGRectGetHeight(rect) - drawingPadding); [heartPath moveToPoint:tipLocation]; // Move to top left start of curve CGPoint topLeftCurveStart = CGPointMake(drawingPadding, floor(CGRectGetHeight(rect) / 2.4)); [heartPath addQuadCurveToPoint:topLeftCurveStart controlPoint:CGPointMake(topLeftCurveStart.x, topLeftCurveStart.y + curveRadius)]; // Create top left curve [heartPath addArcWithCenter:CGPointMake(topLeftCurveStart.x + curveRadius, topLeftCurveStart.y) radius:curveRadius startAngle:M_PI endAngle:0 clockwise:YES]; // Create top right curve CGPoint topRightCurveStart = CGPointMake(topLeftCurveStart.x + 2*curveRadius, topLeftCurveStart.y); [heartPath addArcWithCenter:CGPointMake(topRightCurveStart.x + curveRadius, topRightCurveStart.y) radius:curveRadius startAngle:M_PI endAngle:0 clockwise:YES]; // Final curve to bottom heart tip CGPoint topRightCurveEnd = CGPointMake(topLeftCurveStart.x + 4*curveRadius, topRightCurveStart.y); [heartPath addQuadCurveToPoint:tipLocation controlPoint:CGPointMake(topRightCurveEnd.x, topRightCurveEnd.y + curveRadius)]; [heartPath fill]; heartPath.lineWidth = 1; heartPath.lineCapStyle = kCGLineCapRound; heartPath.lineJoinStyle = kCGLineCapRound; [heartPath stroke]; }
再在所需控制器裏添加ZLLiveHeartView.
- (void)showLiveHeartView { ZLLiveHeartView *heart = [[ZLLiveHeartView alloc]initWithFrame:CGRectMake(0, 0, 40, 40)]; [self.view addSubview:heart]; CGPoint fountainSource = CGPointMake(self.view.frame.size.width - 80, self.view.bounds.size.height - 30 / 2.0 - 10); heart.center = fountainSource; [heart liveHeartAnimateInView:self.view]; }
4. 直播圖片點贊動畫
先自定義ZLLikeAnimation,animatePictureInView方法:
- (void)animatePictureInView:(UIView *)view Image:(UIImage *)image { self.imageView.image = image; NSTimeInterval totalAnimationDuration = 8; CGFloat heartSize = CGRectGetWidth(self.bounds); CGFloat heartCenterX = self.center.x; CGFloat viewHeight = CGRectGetHeight(view.bounds); // Pre-Animation setup self.transform = CGAffineTransformMakeScale(0, 0); self.alpha = 0; // Bloom [UIView animateWithDuration:0.5 delay:0.0 usingSpringWithDamping:0.6 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.transform = CGAffineTransformIdentity; self.alpha = 0.9; } completion:NULL]; NSInteger i = arc4random_uniform(2); // -1 OR 1 NSInteger rotationDirection = 1 - (2 * i); NSInteger rotationFraction = arc4random_uniform(10); [UIView animateWithDuration:totalAnimationDuration animations:^{ self.transform = CGAffineTransformMakeRotation(rotationDirection * M_PI / (16 + rotationFraction * 0.2)); } completion:NULL]; UIBezierPath *heartTravelPath = [UIBezierPath bezierPath]; [heartTravelPath moveToPoint:self.center]; // random end point CGPoint endPoint = CGPointMake(heartCenterX + (rotationDirection) * arc4random_uniform(2 * heartSize), viewHeight/6.0 + arc4random_uniform(viewHeight / 4.0)); // random Control Points NSInteger j = arc4random_uniform(2); NSInteger travelDirection = 1 - (2 * j); // randomize x and y for control points CGFloat xDelta = (heartSize / 2.0 + arc4random_uniform(2 * heartSize)) * travelDirection; CGFloat yDelta = MAX(endPoint.y ,MAX(arc4random_uniform(8 * heartSize), heartSize)); CGPoint controlPoint1 = CGPointMake(heartCenterX + xDelta, viewHeight - yDelta); CGPoint controlPoint2 = CGPointMake(heartCenterX - 2 * xDelta, yDelta); [heartTravelPath addCurveToPoint:endPoint controlPoint1:controlPoint1 controlPoint2:controlPoint2]; CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; keyFrameAnimation.path = heartTravelPath.CGPath; keyFrameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; keyFrameAnimation.duration = totalAnimationDuration + endPoint.y / viewHeight; [self.layer addAnimation:keyFrameAnimation forKey:@"positionOnPath"]; // Alpha & remove from superview [UIView animateWithDuration:totalAnimationDuration animations:^{ self.alpha = 0.0; } completion:^(BOOL finished) { [self removeFromSuperview]; }]; }
再在所需控制器裏添加ZLLikeAnimation.
- (void)showLikePictureView { ZLLikeAnimation *heart = [[ZLLikeAnimation alloc]initWithFrame:CGRectMake(0, 0, 40, 40)]; [self.view addSubview:heart]; CGPoint fountainSource = CGPointMake(self.view.frame.size.width - 80, self.view.bounds.size.height - 30 / 2.0 - 10); heart.center = fountainSource; int count = round(random() % 12); [heart animatePictureInView:self.view Image:[UIImage imageNamed:[NSString stringWithFormat:@"resource.bundle/heart%d.png",count]]]; }
5. 煙花特效:
設置煙花
- (void)setupFireworks { self.caELayer = [CAEmitterLayer layer]; // 發射源 self.caELayer.emitterPosition = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height - 50); // 發射源尺寸大小 self.caELayer.emitterSize = CGSizeMake(50, 0); // 發射源模式 self.caELayer.emitterMode = kCAEmitterLayerOutline; // 發射源的形狀 self.caELayer.emitterShape = kCAEmitterLayerLine; // 渲染模式 self.caELayer.renderMode = kCAEmitterLayerAdditive; // 發射方向 self.caELayer.velocity = 1; // 隨機產生粒子 self.caELayer.seed = (arc4random() % 100) + 1; // cell CAEmitterCell *cell = [CAEmitterCell emitterCell]; // 速率 cell.birthRate = 1.0; // 發射的角度 cell.emissionRange = 0.11 * M_PI; // 速度 cell.velocity = 300; // 範圍 cell.velocityRange = 150; // Y軸 加速度份量 cell.yAcceleration = 75; // 聲明週期 cell.lifetime = 2.04; // 是個CGImageRef的對象,既粒子要展示的圖片 cell.contents = (id)[[UIImage imageNamed:@"ring"] CGImage]; // 縮放比例 cell.scale = 0.2; // 粒子的顏色 cell.color = [[UIColor colorWithRed:0.6 green:0.6 blue:0.6 alpha:1.0] CGColor]; // 一個粒子的顏色green 能改變的範圍 cell.greenRange = 1.0; // 一個粒子的顏色red 能改變的範圍 cell.redRange = 1.0; // 一個粒子的顏色blue 能改變的範圍 cell.blueRange = 1.0; // 子旋轉角度範圍 cell.spinRange = M_PI; // 爆炸 CAEmitterCell *burst = [CAEmitterCell emitterCell]; // 粒子產生係數 burst.birthRate = 1.0; // 速度 burst.velocity = 0; // 縮放比例 burst.scale = 2.5; // shifting粒子red在生命週期內的改變速度 burst.redSpeed = -1.5; // shifting粒子blue在生命週期內的改變速度 burst.blueSpeed= +1.5; // shifting粒子green在生命週期內的改變速度 burst.greenSpeed = +1.0; // 生命週期 burst.lifetime = 0.35; // 火花 and finally, the sparks CAEmitterCell *spark = [CAEmitterCell emitterCell]; // 粒子產生係數,默認爲1.0 spark.birthRate = 400; // 速度 spark.velocity = 125; // 360 deg //周圍發射角度 spark.emissionRange = 2 * M_PI; // gravity //y方向上的加速度份量 spark.yAcceleration = 75; // 粒子生命週期 spark.lifetime = 3; // 是個CGImageRef的對象,既粒子要展示的圖片 spark.contents = (id) [[UIImage imageNamed:@"fireworks"] CGImage]; // 縮放比例速度 spark.scaleSpeed = -0.2; // 粒子green在生命週期內的改變速度 spark.greenSpeed = -0.1; // 粒子red在生命週期內的改變速度 spark.redSpeed = 0.4; // 粒子blue在生命週期內的改變速度 spark.blueSpeed = -0.1; // 粒子透明度在生命週期內的改變速度 spark.alphaSpeed = -0.25; // 子旋轉角度 spark.spin = 2 * M_PI; // 子旋轉角度範圍 spark.spinRange = 2 * M_PI; self.caELayer.emitterCells = [NSArray arrayWithObject:cell]; cell.emitterCells = [NSArray arrayWithObjects:burst, nil]; burst.emitterCells = [NSArray arrayWithObject:spark]; [self.view.layer addSublayer:self.caELayer]; }
6. 雪花特效:
設置雪花
- (void)setupSnowflake { // 建立粒子Layer CAEmitterLayer *snowEmitter = [CAEmitterLayer layer]; // 粒子發射位置 snowEmitter.emitterPosition = CGPointMake(120,0); // 發射源的尺寸大小 snowEmitter.emitterSize = self.view.bounds.size; // 發射模式 snowEmitter.emitterMode = kCAEmitterLayerSurface; // 發射源的形狀 snowEmitter.emitterShape = kCAEmitterLayerLine; // 建立雪花類型的粒子 CAEmitterCell *snowflake = [CAEmitterCell emitterCell]; // 粒子的名字 snowflake.name = @"snow"; // 粒子參數的速度乘數因子 snowflake.birthRate = 20.0; snowflake.lifetime = 120.0; // 粒子速度 snowflake.velocity = 10.0; // 粒子的速度範圍 snowflake.velocityRange = 10; // 粒子y方向的加速度份量 snowflake.yAcceleration = 2; // 周圍發射角度 snowflake.emissionRange = 0.5 * M_PI; // 子旋轉角度範圍 snowflake.spinRange = 0.25 * M_PI; snowflake.contents = (id)[[UIImage imageNamed:@"snow"] CGImage]; // 設置雪花形狀的粒子的顏色 snowflake.color = [[UIColor whiteColor] CGColor]; snowflake.redRange = 1.5f; snowflake.greenRange = 2.2f; snowflake.blueRange = 2.2f; snowflake.scaleRange = 0.6f; snowflake.scale = 0.7f; snowEmitter.shadowOpacity = 1.0; snowEmitter.shadowRadius = 0.0; snowEmitter.shadowOffset = CGSizeMake(0.0, 0.0); // 粒子邊緣的顏色 snowEmitter.shadowColor = [[UIColor whiteColor] CGColor]; // 添加粒子 snowEmitter.emitterCells = @[snowflake]; // 將粒子Layer添加進圖層中 [self.view.layer addSublayer:snowEmitter]; // 造成遮罩 UIImage *image = [UIImage imageNamed:@"alpha"]; _layer = [CALayer layer]; _layer.frame = (CGRect){CGPointZero, self.view.bounds.size}; _layer.contents = (__bridge id)(image.CGImage); _layer.position = self.view.center; snowEmitter.mask = _layer; }
一、壓縮文件截圖
2.項目截圖:
持續更新添加動畫特效~
界面性問題能夠根據本身項目需求調整便可, 具體可參考代碼, 項目可以直接運行!