preface
Today, LET’s write about a “like” effect used in the project. The most important one is this particle animation. I plan to write one myself, because I have referred to several articles and found no ready-made code encapsulated.
The effect displayed by this GIF is different from that displayed on the real machine or simulator. Animation runs smoothly on the simulator and the real machine (LICEcap has problems recently, so it is useless, and the screen recording function on QQ is used instead).
Train of thought
- Selection of controls:
You have click events, you have pictures, you have numbers, you have states,UIButton is the best
- Animation split:
1. Particle animation particles are generated, then spread, and disappear after reaching a certain position (particle animation) 2. Top +1 number, gradient appears, reaches a certain y value hidden (UIView animation or frame animation) 3. The “like” number on the right, hidden from 0, changes opacity to red (UIView animation or frame animation) 4. Button from gray to red needless to say, just set the button image
- Note:
Possible network request problems (network delay of uplike/unuplike operation)
The specific implementation
Particle animation
CAEmitterCell * explosionCell = [CAEmitterCell emitterCell]; // It's explosionCell.alphaSpeed = -1.0; // alphaRange = 0.5; Lifetime = 0.5; // The lifetime explosionCell.lifetime = 0.5; / / particle exists the time range explosionCell. The lifetimeRange = 0.2; // How many particles can be released per cell. BirthRate = 15; // The speed of particle diffusion is explosioncell. velocity = 75.f; / / particle diffusion speed fluctuation range + 10 or - 10. / / explosionCell velocityRange = 10. F. / / maximum - M_PI_4/2 particle emission direction explosionCell. EmissionLongitude = - M_PI_2; explosionCell.emissionRange = M_PI_2; // Particle deform size explosionCell.scale = 0.08; ScaleRange = 0.02; // ExplosionCell.scalerange = 0.02; // Particle content explosionCell.contents = (id)[[UIImage imageNamed:@"spark_red"] CGImage]; Color = [UIColor yellowColor].cgcolor; explosionCell.color = [UIColor redColor].CGColor; RedRange = 10; explosionCell.greenRange = 10; explosionCell.blueRange = 10; RedSpeed = 10; // Blend color explosionCell.redSpeed = 10; explosionCell.greenSpeed = 10; explosionCell.blueSpeed = 10; CAEmitterLayer * explosionLayer = [CAEmitterLayer layer]; [self.layer addSublayer:explosionLayer]; self.explosionLayer = explosionLayer; / / launch position - where particles from the beginning to spread / / self. ExplosionLayer. EmitterSize = CGSizeMake (self. Bounds. Size. Width + 3, self.bounds.size.height + 3); / / the shapes of the emission source explosionLayer emitterShape = kCAEmitterLayerPoint; BirthRate = 0; birthRate = 0; birthRate = 0; / / launch modes: from which position of the particle emitter: a certain point, surface, edge, internal explosionLayer. EmitterMode = kCAEmitterLayerVolume; . / / particle renderer explosionLayer renderMode = kCAEmitterLayerAdditive; explosionLayer.emitterCells = @[explosionCell];Copy the code
1. The core of particle animation is these codes, which create the particle source cell that releases the particle, and the emission source emits these particle source cells, which diffuse the particles and form particle animation
2. After creating the particle source cell, set some properties about the particle source itself, some about the dispersed particles, including the property of Range, which is the floating Range value, namely the interval. For example, lifetime = 0.5, set lifetimeRange = 0.2, then the real life cycle of the particle is 0.3 ~ 0.7, that is, the real life cycle of the particle is the random value of 0.3 ~ 0.7. If the random value has many attributes, the irregular animation will be formed
- EmissionLongitude = -m_PI_2 represents the vertical upward direction
2. Fist animation
Animation.keypath = @”transform.scale”
// enlarge CAKeyframeAnimation; // enlarge CAKeyframeAnimation; // enlarge CAKeyframeAnimation animation]; animation.keyPath = @"transform.scale"; Animation. Values = @ [@ 1.5, @ 2.0, @ 3.5]; Animation. Duration = 0.25; animation.calculationMode = kCAAnimationCubic; Self. BackImageView. Alpha = 0.05; [self.backImageView.layer addAnimation:animationforKey:nil];
}
Copy the code
Three. Two digital animations
CAKeyframeAnimation *animation0 = [CAKeyframeAnimation animation]; animation0.keyPath = @"opacity"; Animation0. Values = @ [@ 0.5, @ 0.8, @ 1.0]; Animation0. Duration = 0.5; animation0.calculationMode = kCAAnimationCubic; [self.incLabel.layer addAnimation:animation0forKey:nil]; // start animation"+ 1"Y = _incOrginY; self.inclabel. y = _incOrginY; // Prevent label from flashing self.inclabel. alpha = 1; / / 2. Add"+ 1"CAKeyframeAnimation *animationScale = [CAKeyframeAnimation animation]; animationScale.keyPath = @"transform.scale"; AnimationScale. Values = @ [@ 1.0, @ 1.1, @ 1.2]; AnimationScale. Duration = 1.0; animationScale.calculationMode = kCAAnimationCubic; [self.incLabel.layer addAnimation:animationScaleforKey:nil]; / / 3. Add"+ 1"S upward displacement animation __weak Typeof (self) weakSelf = self; [UIView animateWithDuration: delay 0.5:0.0 options: UIViewAnimationOptionCurveEaseInOut animations: ^ {weakSelf. IncLabel. Y } completion:^(BOOL finished) {//4"+ 1"CAKeyframeAnimation *animation2 = [CAKeyframeAnimation animation]; animation2.keyPath = @"opacity"; Animation2. Values = @ [@ 0.8, @ 0.5, @ 0]; Animation2. Duration = 0.5; animation2.calculationMode = kCAAnimationCubic; [weakSelf.incLabel.layer addAnimation:animation2forKey:nil];
self.incLabel.alpha = 0;
}];
}
Copy the code
use
- The demo address is at the end of the article
- Use relatively simple, import header file, create button, button Action can be set
#import "RBCLikeButton.h"RBCLikeButton *likeBtn = [[RBCLikeButton alloc] initWithFrame:CGRectMake(130, 200, 100, 100)]; [likeBtnsetImage:[UIImage imageNamed:@"day_like"] forState:UIControlStateNormal];
[likeBtn setImage:[UIImage imageNamed:@"day_like_red"] forState:UIControlStateSelected];
[likeBtn addTarget:self action:@selector(likeBtnClickAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:likeBtn];
Copy the code
- Like the corresponding Action, the code is a little bit longer, but it is attached to the network request and network request to make different conditions of the processing operation, the specific explanation code contains all
Void likeBtnClickAction:(RBCLikeButton *) BTN {//1. BOOL isThump =! btn.isSelected; NSInteger num = btn.thumpNum; //2. //3. Calculate the number of likesif(isThump) { num = num + 1; // The number of likes after the likes}else{ num = num - 1; } //4. Call the "like" animation, set the "like" value of button [BTNsetThumbWithSelected:isThump thumbNum:num animation:YES]; //5. Network requestif(isThump) {isRequestSuccess BOOL isRequestSuccess = YES; // The request succeededif(! IsRequestSuccess) {BTN cancelLike cancelLike; }}else{isRequestSuccess BOOL isRequestSuccess = NO; isRequestSuccess = NO; // The request failedif(! IsRequestSuccess) {// If the operation fails (there is no network or an interface exception) // The "like" value and the status change of the "Like" button are restored. [BTN recoverLike]; }}}Copy the code
Why change the state of the local button first and then make a network request?
- The reason for doing this is to consider the user experience, intuitively show him the results of the operation, so that he can not detect the network request (because there may be network delay).
- We have also prepared recoverLike and cancelLike for network request failures
Pay attention to the point
The “like” Action code isn’t perfect
Because in the actual operation process will appear the user repeatedly crazy click like button operation, and the network request is delayed, so there may be two like requests sent to the server at the same time, although some servers will do restrictions, but your local code logic will be confused, resulting in the number of likes displayed wrong
Solution: Define the status of the like button
typedef enum : NSUInteger {RBCLikeButtonStatusHadThumbs, / / thumb up RBCLikeButtonStatusNoneThumbs, / / not thumb up RBCLikeButtonStatusThumbsing, / / are thumb up RBCLikeButtonStatusCancelThumbsing / / is to cancel the thumb up} RBCLikeButtonStatus;Copy the code
Define status as the like status of the like button
// If status is not"Unlikes in progress."and"I'm liking it."and"Liked"", and then perform the network like requestif( status ! = RBCLikeButtonStatusCancelThumbsing && status ! = RBCLikeButtonStatusThumbsing && status ! = RBCLikeButtonStatusHadThumbs) {/ / change this location button model of thumb up state - > is thumb up status = RBCLikeButtonStatusThumbsing; // Execute network request for likes}Copy the code
// If status is not"Unlikes in progress."and"I'm liking it."and"Not liked."", and then execute the unlike network requestif( status ! = RBCLikeButtonStatusCancelThumbsing && status ! = RBCLikeButtonStatusThumbsing && status ! = RBCLikeButtonStatusNoneThumbs) {/ / change this location button model of thumb up state - > is to cancel the thumb up status = RBCLikeButtonStatusCancelThumbsing; // Execute unlike network request}Copy the code
conclusion
1. If you have friends who have better ideas, you can communicate with the author
2.Demo address: github.com/TynnPassBy/…