What is Preloader?
Preloader is an interesting HUD designed by Volodymyr Kurbatov (Head up Display), which attracts the user's eye tracking through sticky animations between motion stains and fixed stains, effectively dispersing waiting attention.
This article simple analysis I use OC realization preloader principle idea and practice.
Spray out the Grease
According to the sticky characteristics of this loading animation, I put it in the color of the object compared to oil, observing the animation found that it can be divided into two of the whole, the left and right sides two fixed oil, and the movement of three small oil spots, about two fixed oil in turn to each other spray oil, Both sides will become larger because of the absorption of oil, spray oil and become smaller.
First we start with the stains moving around the left and right, because the path is not a smooth one step, I choose to use the Cakeyframeanimation keyframe animation to make a stain that moves back and forth between the left and right fixed points.
12345678910111213141516 |
//moving Spot
for (int i = 0; i < 3; i++) {
Spot *movingSpot = [[Spot alloc] initWithFrame:CGRectMake(originX - UNIT_RADIUS, self.bounds.size.height / 2 - UNIT_RADIUS , 2 * UNIT_RADIUS, 2 * UNIT_RADIUS) color:spotColor];
//1
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@
"position.x"
];
anim.values = @[@(originX), @(originX), @(finalX), @(finalX), @(originX), @(originX)];
anim.keyTimes = @[@(0.0), @(0.25), @(0.35), @(0.75), @(0.85), @(1.0)];
//sleep 0.4 ratio
anim.duration = PROCESS_DURING;
anim.repeatCount = HUGE_VALF;
anim.beginTime = CACurrentMediaTime() + i * SPOT_DELAY_RATIO * PROCESS_DURING;
[movingSpot.layer addAnimation:anim forKey:@
"movingAnim"
];
[self addSubview:movingSpot];
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction commit];
}
|
I removed the superfluous code, mainly we look at//1 Place, first take a stain to do the reference , we through the Cakeyframeanimation control the position.x change of the stain layer, the formation of animation. Now we only need two control points (Originx, finalx), the path can be resolved to: "Rest, left starting point, to the right end point, rest, and then back to the left starting point," This action chain for a loop. Look at our keytimes and values why are these numbers? Here we only need to guarantee two points:
This is where I set the stain break to 0.4 units, so the move Time is (1-2*0.4)/2 = 0.1 units. Here are two questions:
Why start moving from 0.25 units instead of 0.0? Maybe I just want to keep the flexibility for the back, it doesn't really matter much.
Why are there two duplicate originx in front of the values, followed by two duplicate finalx? This is a must, Although the value of Cakeyframeanim does not need to end from 0.0 start 1.0 can also achieve the same animation effect, but if there is no such two poles, the animation in real-time position through the Presentationlayer will be more than the incorrect boundary of the negative number, will later mention this issue.
Some friends may not be able to understand this animation path corresponding to the stain rest time where, here again strengthen, 0.35-0.75 on the right to rest, 0.85-0.25 on the left to rest, staring at my code to see, will understand.
OK, we have understood a stain of the animation path, then we use a for loop, very simple can make three, one with a starting stain animation path, to ensure that the previous foundation, here only need to ensure that three path animation one cycle duration duration the same, Then we use a delay factor of spot_delay_ratio = 0.08f, control 3 animation respectively of the BeginTime, achieve a follow one effect.
Absorbs oil, sprays oil
Next we do two fixed stains of the big and small animation, of course, can not be used to do collision detection, so bad control and affected by the size, there will be a lot of unnecessary code. The idea is to do a specific size change at a specific time, since we have defined the spot moving and resting keyframe keyframe, why not continue to use them? Look at the animated code that fixed the grease:
12345678910111213141516171819202122232425262728293031 |
//Fixed Spot
Spot *leftFixedSpot = [[Spot alloc] initWithFrame:CGRectMake(originX - UNIT_RADIUS, self.bounds.size.height / 2 - UNIT_RADIUS, 2 * UNIT_RADIUS, 2 * UNIT_RADIUS) color:spotColor];
Spot *rightFixedSpot = [[Spot alloc] initWithFrame:CGRectMake(self.bounds.size.width - margin - UNIT_RADIUS, self.bounds.size.height / 2 - UNIT_RADIUS, 2 * UNIT_RADIUS, 2 * UNIT_RADIUS) color:spotColor];
NSValue *firstVal = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0)];
NSValue *secondVal = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.0f, 2.0f, 0)];
NSValue *thirdVal = [NSValue valueWithCATransform3D:CATransform3DMakeScale(3.0f, 3.0f, 0)];
NSValue *fourthVal = [NSValue valueWithCATransform3D:CATransform3DMakeScale(4.0f, 4.0f, 0)];
//发射点,先调至最大
leftFixedSpot.layer.transform = CATransform3DMakeScale(4.0f, 4.0f, 0);
//left
CAKeyframeAnimation *leftFixedSpotAnim = [CAKeyframeAnimation animationWithKeyPath:@
"transform"
];
leftFixedSpotAnim.values = @[thirdVal, thirdVal, fourthVal, fourthVal, thirdVal, thirdVal, secondVal, secondVal, firstVal,
firstVal, secondVal, secondVal, thirdVal, thirdVal];
leftFixedSpotAnim.keyTimes = @[@(0.0), @(0.01), @(0.01), @(0.25), @(0.25), @(0.33), @(0.33), @(0.41), @(0.41),
//sleep
@(0.85), @(0.85), @(0.93), @(0.93), @(1.00)];
//SPOT_DELAY_RATIO = 0.08
leftFixedSpotAnim.duration = PROCESS_DURING;
leftFixedSpotAnim.repeatCount = HUGE_VALF;
[leftFixedSpot.layer addAnimation:leftFixedSpotAnim forKey:@
"fixedSpotScaleAnim"
];
//right
CAKeyframeAnimation *rightFixedSpotAnim = [CAKeyframeAnimation animationWithKeyPath:@
"transform"
];
rightFixedSpotAnim.values = @[firstVal, firstVal, secondVal, secondVal, thirdVal, thirdVal, fourthVal,
fourthVal, thirdVal, thirdVal, secondVal, secondVal, firstVal, firstVal];
rightFixedSpotAnim.keyTimes = @[@(0.0), @(0.25), @(0.25), @(0.33), @(0.33), @(0.41), @(0.41),
//sleep
@(0.75), @(0.75), @(0.83), @(0.83), @(0.91), @(0.91), @(1.0)];
//SPOT_DELAY_RATIO = 0.08
rightFixedSpotAnim.duration = PROCESS_DURING;
rightFixedSpotAnim.repeatCount = HUGE_VALF;
//0.1 ratio needed that the spot from left to right
rightFixedSpotAnim.beginTime = CACurrentMediaTime() + PROCESS_DURING * 0.1;
[rightFixedSpot.layer addAnimation:rightFixedSpotAnim forKey:@
"fixedSpotScaleAnim"
];
[self addSubview:leftFixedSpot];
[self addSubview:rightFixedSpot];
|
We first define the 4 scale corresponding blot value (Firstval, Secondval, Thirdval, Fourthval), using Keyframeanimation to control the change of these 4 kinds of value, To achieve a fixed stain at a specified point in time to become larger and smaller.
Here's what to note:
Consistent with a moving stain, also starting from 0.25
Remember moving the stain one with a starting delay factor of 0.08f? It's a unit of time between fixed spots getting bigger and smaller.
Since moving the stain moves from side to side with a time unit of 0.1, the animation start time of the right fixed point is 0.1 later than the left fixed point, which is Rightfixedspotanim.begintime = Cacurrentmediatime () + Process_during * 0.1;
Moving a spot break is not necessary on a fixed-point keyframe, because the fixed point becomes the smallest after the last moving stain leaves, while the first moving stain is temporarily going to start getting bigger.
Since the animation of the right fixed point has been delayed by 0.1 relative to the left anchor point, it is still active from 0.25 keyframes (becomes larger)
Here is an example of how this part key frame is calculated based on:
Look at the left fixed point code//left, starting from 0.25 activity, each over a delay factor of 0.08, there will be a spot trigger (squirting), do a small animation, when the third small animation is done, we do not know how long the middle rest time, then we need to use 0.85 this keyframe time ( From the mobile stain code can be seen, the first stain in 0.85 back to the left fixed point, so from 0.85 to do the big animation, is also the delay factor of 0.08, the last operation of 1.0, no matter the impact is not small, the last big animation in 0.01 do just fine!
What about the 0.75 keyframes of the right fixed point? 0.41 is the last time it gets bigger (the last stain is absorbed), then the interval from which the first stain is sprayed is the 0.41+ move stain break time 0.4-two delay factor 0.08*2, because when the last stain is absorbed, the first stain has rested two delay factor time.
Slow expansion of large
The Keyframeanim change of the scale before is abrupt, one scale jumps to the other scale, take a look at the local code meeting under:
12 |
firstVal, secondVal, secondVal, thirdVal @(0.25), @(0.25), @(0.33), @(0.33) |
It can be seen that a Val change to another Val is happening at the same keyframe, without undue effect. For ease of modification, we only need to introduce a short animation interval cgfloat ti = spot_magnify_anim_duration_ratio = 0.03f:
123 |
CGFloat ti = SPOT_MAGNIFY_ANIM_DURATION_RATIO; leftFixedSpotAnim.keyTimes = @[@(0.0), @(0.01), @(0.01+ti), @(0.25), @(0.25+ti), @(0.33), @(0.33+ti), @(0.41), @(0.41+ti), //sleep @(0.85), @(0.85+ti), @(0.93), @(0.93+ti), @(1.00)]; //SPOT_DEL |
Sticky animations
Here I use Presentationlayer to get the real-time frame information of the animation layer, and then prepare several tool functions:
Centerdistancewithpoint:another: Calculate Center Distance CD
Facedistancewithcirclelayer:another: Calculating surface distance FD
Circleincirclingwithbigone:smallone: Judging whether the two circles contain a relationship
I used Cashapelayer and uibezierpath to do this adhesion effect, by controlling the color of the Cashapelayer to control the display and disappearance of adhesion, and the display/disappearance is based on the two-circle surface distance FD. Here again the Keyframeanim Keytimes must start at 0.0 and end in 1.0, otherwise there will be incorrect data interference when acquiring a layer real frame.
So what does "include" for? We have 3 stains, a adhesion effect shapelayer, when the third stain arrives according to FD to calculate the adhesion path, ready to express themselves happily, this path will be the first blot of FD interference, calculate an incorrect path coverage, So we let the moving stain and the fixed stain inside cut, not affect the adhesion path. By the way, all of these animated logic calculations are done in Cadisplaylink.
Path:
We use two curves to join the two circle of this stain binding as the animation path (see), this way can be a good simulation of the absorption and binding effect of the liquid, the curve through the fixed spot of vertex Fu and moving the point mu of the stain, A curve is determined by a controlpoint on the perpendicular bisector of the Fumu segment. Uibezierpath's API:addQuadCurveToPoint:controlPoint:. The entire path consists of a curve Fumu, a curve FDMD, and an arc MUMD, and finally the segment FUFD closed. Absorption effect:
Rebound Sticky effect
Before we do the rebound effect, we have to let the moving stain run to the back of the fixed stain, introduce Originrearx (rear of the starting point) and Finalrearx (rear end), modify the Keyframeanim of the Moving stain:
1234 |
anim.values = @[@(originX), @(originX), @(finalX), @(finalRearX), @(finalX), @(finalX), @(originX), @(originRearX), @(originX), @(originX)]; anim.keyTimes = @[@(0.0), @(0.25), @(0.35), @(0.38), @(0.41), @(0.75), @(0.85), @(0.88), @(0.91), @(1.0)]; //sleep 0.4 ratio |
As you can see in the code, I've defined a rebound time of 0.03 * 2,ok There's no problem here.
As for the effect of the rebound path, because the two spots of the center of the distance is relatively small, if still follow the previous path scheme effect will not be very good, we use this path and no longer use the simulated liquid absorption curve mode. For reference, we combine the sticky effect path with two segments, and an arc coincident with the moving stain circumference, which is then closed by the segment FUFD, and the segment passes through the left fixed stain, tangent to the overflow moving stain.
Remember "whether or not to include", moving the stain from the back of the fixed stain is not in line with the inclusion of the relationship, will affect the positive adhesion effect of the painting, so the rebound sticky effect here with the ordinary sticky effect of two separate cashapelayer to do, to avoid interference. Rebound Effect:
The general idea is this, the main time-consuming task is to calculate the path and coordinate the display of several cashapelayer and mutual influence, source code demo:http://download.csdn.net/my
Use Preloader to achieve a head-up display (HUD) effect (can be applied to the load wait effect), and simple explanation