我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛
实现效果:
思路:
1、生成一个红包layer
self.animationLayer = [CALayer new];
self.animationLayer.bounds = imageV.frame;
self.animationLayer.anchorPoint = CGPointMake(0, 0);
self.animationLayer.position = CGPointMake(0, -52.5 );
self.animationLayer.contents = (id)imageV.image.CGImage;
[self.touchView.layer addSublayer:self.animationLayer];
2、添加layer的动画
- (void)addAnimation
{
CAKeyframeAnimation * moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
NSValue * A = [NSValue valueWithCGPoint:CGPointMake(arc4random() % 414, 0)];
NSValue * B = [NSValue valueWithCGPoint:CGPointMake(arc4random() % 414, [UIScreen mainScreen].bounds.size.height)];
moveAnimation.values = @[A,B];
moveAnimation.duration = arc4random() % 200 / 100.0 + 3.5;
moveAnimation.repeatCount = 1;
moveAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[self.animationLayer addAnimation:moveAnimation forKey:nil];
CAKeyframeAnimation * tranAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
CATransform3D r0 = CATransform3DMakeRotation(M_PI/180 * (arc4random() % 360 ) , 0, 0, -1);
CATransform3D r1 = CATransform3DMakeRotation(M_PI/180 * (arc4random() % 360 ) , 0, 0, -1);
tranAnimation.values = @[[NSValue valueWithCATransform3D:r0],[NSValue valueWithCATransform3D:r1]];
tranAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
tranAnimation.duration = arc4random() % 200 / 100.0 + 3.5;
//为了避免旋转动画完成后再次回到初始状态。
[tranAnimation setFillMode:kCAFillModeForwards];
[tranAnimation setRemovedOnCompletion:NO];
[self.animationLayer addAnimation:tranAnimation forKey:nil];
}
3、定时生成红包
- (void)startRedPackerts
{
if (self.timer) {
[self.timer invalidate];
}
self.timer= nil;
self.timer = [NSTimer scheduledTimerWithTimeInterval:(1/2.0) target:self selector:@selector(showRain) userInfo:nil repeats:YES];
}
4、判断红包点击事件
- (void)clickRed:(UITapGestureRecognizer *)sender
{
CGPoint point = [sender locationInView:self.touchView];
for (int i = 0 ; i < self.touchView.layer.sublayers.count ; i ++)
{
CALayer * layer = self.touchView.layer.sublayers[i];
if ([[layer presentationLayer] hitTest:point] != nil)
{
NSLog(@"%d",i);
BOOL hasRedPacketd = !(i % 2) ;
UIImageView * newPacketIV = [UIImageView new];
if (hasRedPacketd)
{
newPacketIV.image = [UIImage imageNamed:@"moon_cake"];
newPacketIV.backgroundColor = [UIColor redColor];
newPacketIV.frame = CGRectMake(0, 0, 63.5, 74);
}
else
{
newPacketIV.image = [UIImage imageNamed:@"moon_cry"];
newPacketIV.backgroundColor = [UIColor greenColor];
newPacketIV.frame = CGRectMake(0, 0, 45.5, 76.5);
}
layer.contents = (id)newPacketIV.image.CGImage;
UIView * alertView = [UIView new];
alertView.layer.cornerRadius = 5;
alertView.frame = CGRectMake(point.x - 50, point.y, 100, 30);
[self.touchView addSubview:alertView];
UILabel * label = [UILabel new];
label.font = [UIFont systemFontOfSize:17];
if (!hasRedPacketd)
{
label.text = @"嘤嘤嘤!旺旺旺";
label.textColor = [UIColor blackColor];
}
else
{
NSString * string = [NSString stringWithFormat:@"+%d月饼券",i];
NSString * iString = [NSString stringWithFormat:@"%d",i];
NSMutableAttributedString * attributedStr = [[NSMutableAttributedString alloc]initWithString:string];
[attributedStr addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:27]
range:NSMakeRange(0, 1)];
[attributedStr addAttribute:NSFontAttributeName
value:[UIFont fontWithName:@"PingFangTC-Semibold" size:32]
range:NSMakeRange(1, iString.length)];
[attributedStr addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:17]
range:NSMakeRange(1 + iString.length, 2)];
label.attributedText = attributedStr;
label.textColor = [UIColor blueColor];
}
[alertView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(alertView.mas_centerX);
make.centerY.equalTo(alertView.mas_centerY);
}];
[UIView animateWithDuration:1 animations:^{
alertView.alpha = 0;
alertView.frame = CGRectMake(point.x- 50, point.y - 100, 100, 30);
} completion:^(BOOL finished) {
[alertView removeFromSuperview];
}];
}
}
}
5、停止红包雨
- (void)endAnimation
{
[self.timer invalidate];
for (NSInteger i = 0; i < self.touchView.layer.sublayers.count ; i ++)
{
CALayer * layer = self.touchView.layer.sublayers[i];
[layer removeAllAnimations];
}
}
总结,注意事项:
- 倒计时用 NSTimer实现。
- 红包雨的动画用CALayer来实现。。
- 动画分为两个部分,第一个部分是位移动画,第二部分是旋转动画。
- 红包下落完成后,关闭倒计时,移除layer动画。
- UIView可以响应事件,但是CALayer不行。可以给背景视图添加手势,然后根据手势的落点,来判断是第几个红包。
所有代码
//
// ViewController.m
// mooncake
//
// Created by on 2021/9/17.
//
#import "ViewController.h"
#import <Masonry/Masonry.h>
@interface ViewController ()
@property (nonatomic, strong) UILabel *countdownLabel;
@property (nonatomic, strong) CALayer *animationLayer;
@property (nonatomic, strong) UIView *touchView;
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation ViewController
- (UIView *)touchView{
if (_touchView == nil) {
_touchView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickRed:)];
[_touchView addGestureRecognizer:gesture];
}
return _touchView;
}
- (UILabel *)countdownLabel
{
if (_countdownLabel == nil) {
_countdownLabel = [[UILabel alloc] initWithFrame:CGRectMake(([UIScreen mainScreen].bounds.size.width - 200)*0.5, ([UIScreen mainScreen].bounds.size.height - 200)*0.5, 200, 200)];
_countdownLabel.font = [UIFont systemFontOfSize:80 weight:UIFontWeightBold];
_countdownLabel.textAlignment = NSTextAlignmentCenter;
}
return _countdownLabel;
}
- (void)startTime
{
__block int timeout = 5;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0);
dispatch_source_set_event_handler(_timer, ^{
if ( timeout <= 0 )
{
dispatch_source_cancel(_timer);
dispatch_async(dispatch_get_main_queue(), ^{
[self startRedPackerts];
self.countdownLabel.hidden = YES;
});
}
else
{
NSString * titleStr = [NSString stringWithFormat:@"%d",timeout];
dispatch_async(dispatch_get_main_queue(), ^{
self.countdownLabelcountdownLabelcountdownLab.text = titleStr;
});
timeout--;
}
});
dispatch_resume(_timer);
}
- (void)startRedPackerts
{
if (self.timer) {
[self.timer invalidate];
}
self.timer= nil;
self.timer = [NSTimer scheduledTimerWithTimeInterval:(1/2.0) target:self selector:@selector(showRain) userInfo:nil repeats:YES];
}
- (void)showRain
{
UIImageView * imageV = [UIImageView new];
imageV.image = [UIImage imageNamed:@"red_pocket"];
imageV.frame = CGRectMake(0, 0, 40 , 52.5 );
self.animationLayer = [CALayer new];
self.animationLayer.bounds = imageV.frame;
self.animationLayer.anchorPoint = CGPointMake(0, 0);
self.animationLayer.position = CGPointMake(0, -52.5 );
self.animationLayer.contents = (id)imageV.image.CGImage;
[self.touchView.layer addSublayer:self.animationLayer];
[self addAnimation];
}
- (void)addAnimation
{
CAKeyframeAnimation * moveAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
NSValue * A = [NSValue valueWithCGPoint:CGPointMake(arc4random() % 414, 0)];
NSValue * B = [NSValue valueWithCGPoint:CGPointMake(arc4random() % 414, [UIScreen mainScreen].bounds.size.height)];
moveAnimation.values = @[A,B];
moveAnimation.duration = arc4random() % 200 / 100.0 + 3.5;
moveAnimation.repeatCount = 1;
moveAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[self.animationLayer addAnimation:moveAnimation forKey:nil];
CAKeyframeAnimation * tranAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
CATransform3D r0 = CATransform3DMakeRotation(M_PI/180 * (arc4random() % 360 ) , 0, 0, -1);
CATransform3D r1 = CATransform3DMakeRotation(M_PI/180 * (arc4random() % 360 ) , 0, 0, -1);
tranAnimation.values = @[[NSValue valueWithCATransform3D:r0],[NSValue valueWithCATransform3D:r1]];
tranAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
tranAnimation.duration = arc4random() % 200 / 100.0 + 3.5;
//为了避免旋转动画完成后再次回到初始状态。
[tranAnimation setFillMode:kCAFillModeForwards];
[tranAnimation setRemovedOnCompletion:NO];
[self.animationLayer addAnimation:tranAnimation forKey:nil];
}
- (void)endAnimation
{
[self.timer invalidate];
for (NSInteger i = 0; i < self.touchView.layer.sublayers.count ; i ++)
{
CALayer * layer = self.touchView.layer.sublayers[i];
[layer removeAllAnimations];
}
}
- (void)clickRed:(UITapGestureRecognizer *)sender
{
CGPoint point = [sender locationInView:self.touchView];
for (int i = 0 ; i < self.touchView.layer.sublayers.count ; i ++)
{
CALayer * layer = self.touchView.layer.sublayers[i];
if ([[layer presentationLayer] hitTest:point] != nil)
{
NSLog(@"%d",i);
BOOL hasRedPacketd = !(i % 2) ;
UIImageView * newPacketIV = [UIImageView new];
if (hasRedPacketd)
{
newPacketIV.image = [UIImage imageNamed:@"moon_cake"];
newPacketIV.backgroundColor = [UIColor redColor];
newPacketIV.frame = CGRectMake(0, 0, 63.5, 74);
}
else
{
newPacketIV.image = [UIImage imageNamed:@"moon_cry"];
newPacketIV.backgroundColor = [UIColor greenColor];
newPacketIV.frame = CGRectMake(0, 0, 45.5, 76.5);
}
layer.contents = (id)newPacketIV.image.CGImage;
UIView * alertView = [UIView new];
alertView.layer.cornerRadius = 5;
alertView.frame = CGRectMake(point.x - 50, point.y, 100, 30);
[self.touchView addSubview:alertView];
UILabel * label = [UILabel new];
label.font = [UIFont systemFontOfSize:17];
if (!hasRedPacketd)
{
label.text = @"嘤嘤嘤!旺旺旺";
label.textColor = [UIColor blackColor];
}
else
{
NSString * string = [NSString stringWithFormat:@"+%d月饼券",i];
NSString * iString = [NSString stringWithFormat:@"%d",i];
NSMutableAttributedString * attributedStr = [[NSMutableAttributedString alloc]initWithString:string];
[attributedStr addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:27]
range:NSMakeRange(0, 1)];
[attributedStr addAttribute:NSFontAttributeName
value:[UIFont fontWithName:@"PingFangTC-Semibold" size:32]
range:NSMakeRange(1, iString.length)];
[attributedStr addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:17]
range:NSMakeRange(1 + iString.length, 2)];
label.attributedText = attributedStr;
label.textColor = [UIColor blueColor];
}
[alertView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(alertView.mas_centerX);
make.centerY.equalTo(alertView.mas_centerY);
}];
[UIView animateWithDuration:1 animations:^{
alertView.alpha = 0;
alertView.frame = CGRectMake(point.x- 50, point.y - 100, 100, 30);
} completion:^(BOOL finished) {
[alertView removeFromSuperview];
}];
}
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.countdownLabel];
[self.view addSubview:self.touchView];
[self startTime];
}
@end