First, the effect picture:
Animation – Realize the loop playback Animation, can control the number of times
For example, the expectation is as follows:
If you’re using View animations, the natural choice is to do it in an XML file under RES /anim, and to combine animations, use the set tag.
Does that actually work? Let’s practice step by step. In advance of the plot, the official website demo is also problematic.
If you are in a hurry and just want to see the solution, you can move directly to the last step of the demo.
1, use,res/anim
Under the XML file to achieve the combination of animation sequential execution of the pit.
The sequential execution of the animations depends on the startOffset property, whose value is equal to the sum of the duration of all previous animations. Our most intuitive implementation code is as follows:
<? The XML version = "1.0" encoding = "utf-8"? > <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> <scale Android :duration="200" Android :fromXScale="1.0" Android :fromYScale="1.0" Android :pivotX="50%" Android :pivotY="50%" Android :repeatCount=" @INTEGER/breath_anim_REPEAT_count "Android :toXScale="0.9" Android :toYScale="0.9" /> <scale Android :duration="400" Android :fromXScale="0.9" Android :fromYScale="0.9" Android :pivotX="50%" Android :pivotY="50%" Android: repeatCount = "@ integer/breath_anim_repeat_count" android: startOffset = "200" android: toXScale = "1.1" ToYScale ="1.1" /> <scale android:duration="400" Android :fromXScale="1.1" Android :fromYScale="1.1" android:pivotX="50%" android:pivotY="50%" android:repeatCount="@integer/breath_anim_repeat_count" Android :startOffset="600" Android :toXScale="0.9" Android :toYScale="0.9" /> <scale android:duration="200" Android: fromXScale = "0.9" android: fromYScale = "0.9" android: pivotX = "50%" android: pivotY = "50%" Android: repeatCount = "@ integer/breath_anim_repeat_count" android: startOffset = "1000" android: toXScale = "1.0" Android: toYScale = "1.0" / > < / set >Copy the code
However, there is a problem with the actual execution of this animation. The fromXScale and fromYScale of the second scale code will be applied to the View at the beginning of the set animation, not after the startOffset time as expected.
While the startOffset property delays the execution of the animation, the fromXScale and fromYScale values do not delay and affect the initial state of the set animation from the start of the animation.
Website demo have the same problem: developer.android.com/guide/topic…
Solution:
Change fromXScale and fromYScale for subsequent animations to 1.0, otherwise it will affect the initial state of the animation. Then dynamically convert the toXScale and toYScale ratio of the corresponding animation.Copy the code
The results of the transformation are shown in the following table:
The order | duration | fromXScale | toXScale | fromYScale | toYScale | The transformed fromXScale | ToXScale after conversion | Transformed fromYScale | ToYScale after conversion |
---|---|---|---|---|---|---|---|---|---|
1 | 200 | 1.0 | 0.9 | 1.0 | 0.9 | 1.0 | 1.0 | 0.9 | 0.9 |
2 | 400 | 0.9 | 1.1 | 0.9 | 1.1 | 1.0 | 1.0 | 1.2222222222222223 | 1.2222222222222223 |
3 | 400 | 1.1 | 0.9 | 1.1 | 0.9 | 1.0 | 1.0 | 0.8181818181818181 | 0.8181818181818181 |
4 | 200 | 0.9 | 1.0 | 0.9 | 1.0 | 1.0 | 1.0 | 1.1111111111111112 | 1.1111111111111112 |
2. Pit of -repeatcount:
① Setting repeatCount to set is invalid. (2) If we set repeatCount for each element in the set, each animation will execute its own repeatCount independently, instead of executing the next animation after the first animation sequence. Instead, each Scale element immediately executes its next animation, so that the animation looks clunky and not as expected.
Workaround: Set repeatCount to 0 for each individual scale element. The specific repeatCount logic depends on the code to implement it dynamically.
3. Cancel and stop the animation pit.
There are three ways to cancel an animation: Animation#cancel(), View#clearAnimation(), and View#setAnimation(null), each of which has its advantages and disadvantages. 1) Animation# cancel () will trigger the Animation. AnimationListener# onAnimationEnd callback, not suitable for Animation. AnimationListener# onAnimationEnd calls in the callback. (2) View# clearAnimation () will trigger the Animation. AnimationListener# onAnimationEnd callback, Doesn’t fit in the same Animation. AnimationListener# onAnimationEnd calls in the callback. . (3) View# setAnimation (null) will not trigger the Animation AnimationListener# onAnimationEnd callback, but it may lead to the next call Animation# failed to start.
4, Animation. AnimationListener to monitor the end of the Animation callback.
Animation. AnimationListener# onAnimationEnd method, main is to call the timing is not in line with expectations.
Reference: stackoverflow.com/questions/5…
1) Animation# cancel () and View# clearAnimation () will trigger the Animation. AnimationListener# onAnimationEnd callback, And in Animation. AnimationListener# onAnimationEnd method, Animation# hasEnded () method returns false, do not agree with true expectations.
(2) in the Animation. AnimationListener# onAnimationEnd call Animation# start method when you start the next Animation, Immediately call Animation. AnimationListener# onAnimationStart and Animation AnimationListener# onAnimationEnd callback, the interval is only 1 ms, this will lead to less performs a Animation, Not up to expectations.
Animation. Solution: not recommended AnimationListener to listen on end of the Animation, it is recommended to use Handler# postDelay method + View# clearAnimation ways to implement RepeatCount function.
Final solution: ① In the XML file of RES/ANIM, in addition to using startOffset to ensure the execution order, it is also necessary to convert fromXScale, fromYScale, toXScale and toYScale. Ensure fromXScale and fromYScale are always 1.0. ② use Handler#postDelay method to implement repeatCount function. ③ use View#clearAnimation to clear the animation. ④ When starting the animation again, use the Animation#reset() method to reset the state, and then Animation#start() method to start the animation.
Final solution: Custom BreathAnimHelper.
See BreathAnimHelper for an implementation.