I had the opportunity to implement a "look like floating" animation on Android. It looks like the following image.
This animation
Is realized by executing "continuously" and "repeatedly". "Continuously" means that when the animation in 1. is finished, the animation in 2. is started.
If you do this with Android's View animation API, it's usually terrible code. Next is that.
//Animation that moves up over 2 seconds
final TranslateAnimation anim1 = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -0.1f);
anim1.setDuration(2000);
//Animation that moves down over 2 seconds
final TranslateAnimation anim2 = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -0.1f,
Animation.RELATIVE_TO_SELF, 0.0f);
anim2.setDuration(2000);
anim1.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation) {
anim2.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) { }
@Override
public void onAnimationEnd(Animation animation) {
// 3.When the down animation is over, start the up animation again
view.startAnimation(anim1);
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
// 2.When the animation to the top is finished, start the animation to move down
view.startAnimation(anim2);
}
@Override
public void onAnimationRepeat(Animation animation) { }
});
// 1.Start animation to move up
view.startAnimation(anim1);
The double pain of nesting callbacks is that the process you want to do and the order in which the code is written are reversed, which cannot be done.
This is the only case where you want to use Kotlin (it's better if you use the library
As @glayash commented, if you repeat the animation like this one, you can write it as follows, so it doesn't become a callback hell and you didn't even have to use Kotlin.
//Animation that moves up over 2 seconds
final TranslateAnimation anim1 = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -0.1f);
anim1.setDuration(2000);
//Invert and repeat infinitely
anim1.setRepeatMode(Animation.REVERSE);
anim1.setRepeatCount(Animation.INFINITE);
view.startAnimation(anim1);
That's why I tried it with Kotlin.
First, create a "function that runs the animation and continues to the next when the animation is finished".
Here, I defined it as an extension function of View
.
package net.amay077.animsample
import android.view.View
import android.view.animation.Animation
import kotlin.coroutines.experimental.suspendCoroutine
suspend fun View.startAnimationAsync(anim: Animation) {
return suspendCoroutine { continuation ->
anim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) { }
override fun onAnimationEnd(animation: Animation?) {
continuation.resume(Unit)
}
override fun onAnimationRepeat(animation: Animation?) { }
})
this.startAnimation(anim)
}
}
The caller looks like this:
Heaven compared to Java in callback hell, here ...
It seems that you need to use launch (UI) {}
instead of ```async () {} `` because the animation needs to be called from the UI thread.
val button1 = findViewById(R.id.button1)
val anim1 = TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -0.5f)
anim1.duration = 2000
val anim2 = TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, -0.5f,
Animation.RELATIVE_TO_SELF, 0.0f)
anim2.duration = 2000
launch(UI) { //I'll async from the main thread
//Repeat all the time
while (true) {
button1.startAnimationAsync(anim1) // 1.Run an animation that moves up over 2 seconds
button1.startAnimationAsync(anim2) // 2.Perform an animation that moves down over 2 seconds
}
}
It's my first time to use Kotlin properly, so maybe I can still improve it. .. Please point out any good code.
For implementation in Kotlin, I referred to the following site
C # (ie Xamarin.Android) can also be achieved with a combination of ʻasync / await (ie Task)
and
`TaskCompletionSource``.
C # also has an extension method that you can define as follows:
public static class ViewAnimationExtensions
{
public static Task<bool> StartAnimationAsync(this View view, Animation anim)
{
var source = new TaskCompletionSource<bool>();
EventHandler<Animation.AnimationEndEventArgs> handler = null;
handler = (sender, e) =>
{
anim.AnimationEnd -= handler; //Don't forget to unsubscribe
source.SetResult(true); //kotlin continuation.resume(Unit)Toko
};
anim.AnimationEnd += handler; //Subscribe to the event
view.StartAnimation(anim);
return source.Task;
}
}
This is the start side.
Add the ʻawait`` keyword on the call, and add the
ʻasync keyword to the method that contains it (here `ʻOnCreate
).
protected async override void OnCreate(Bundle savedInstanceState)
{
/*abridgement*/
while (true)
{
await button1.StartAnimationAsync(anim1);
await button1.StartAnimationAsync(anim2);
}
}
It would be nice if Kotlin could be mixed with Java in the same project.
Recommended Posts