[JAVA] Eine Geschichte, die es Kotlin bequem machte, dass es mühsam ist, Animationen kontinuierlich auf Android auszuführen

Ich hatte die Möglichkeit, eine "Look like Floating" -Animation auf Android zu implementieren. Es sieht aus wie das folgende Bild.

Diese Animation

  1. Bewegen Sie sich etwas mehr als 2 Sekunden nach oben
  2. Bewegen Sie sich etwas mehr als 2 Sekunden nach unten

Wird durch Ausführen von "kontinuierlich" und "wiederholt" realisiert. "Kontinuierlich" bedeutet, dass nach Abschluss der Animation von 1. die Animation von 2. gestartet wird.

Java-On Android ...

Dies mit der View-Animations-API von Android zu tun, ist normalerweise schrecklicher Code. Als nächstes kommt das.

//Animation, die sich über 2 Sekunden nach oben bewegt
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, die sich über 2 Sekunden nach unten bewegt
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.Wenn die Abwärtsanimation beendet ist, starten Sie die Aufwärtsanimation erneut
                view.startAnimation(anim1);
            }

            @Override
            public void onAnimationRepeat(Animation animation) { }
        });

        // 2.Wenn die Aufwärtsanimation beendet ist, starten Sie die Abwärtsanimation
        view.startAnimation(anim2);
    }

    @Override
    public void onAnimationRepeat(Animation animation) { }
});

// 1.Starten Sie die Animation, um nach oben zu gelangen
view.startAnimation(anim1);

Der doppelte Schmerz beim Verschachteln von Rückrufen besteht darin, dass der gewünschte Prozess und die Reihenfolge, in der Sie den Code schreiben, umgekehrt sind, was nicht möglich ist.

Dies ist der einzige Fall, in dem Sie Kotlin verwenden möchten (es ist besser, wenn Sie die Bibliothek verwenden, die sowohl Java als auch Deferred verwenden kann).

(Ich musste nicht einmal Kotlin benutzen ...)

Wie @glayash kommentierte, können Sie, wenn Sie die Animation wie diese wiederholen, wie folgt schreiben, damit sie nicht zur Hölle des Rückrufs wird und Sie Kotlin nicht einmal verwenden mussten.

//Animation, die sich über 2 Sekunden nach oben bewegt
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);
//Invertieren und auf unbestimmte Zeit wiederholen
anim1.setRepeatMode(Animation.REVERSE);
anim1.setRepeatCount(Animation.INFINITE);
view.startAnimation(anim1);

Wenn das Kotlin ist ...

Deshalb habe ich es mit Kotlin versucht.

Erstellen Sie zunächst eine "Funktion, die die Animation ausführt und nach Abschluss der Animation mit der nächsten fortfährt". Hier habe ich es als Erweiterungsfunktion von View definiert.

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)
    }
}

Der Anrufer sieht folgendermaßen aus: Dies ist der Himmel im Vergleich zu Java in Callback Hell ... Es scheint, dass Sie launch (UI) {} anstelle von async () {} verwenden müssen, da die Animation vom UI-Thread aufgerufen werden muss.

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) { //Ich werde vom Haupt-Thread asynchronisieren
    //Wiederholen Sie die ganze Zeit
    while (true) {
        button1.startAnimationAsync(anim1) // 1.Führen Sie eine Animation aus, die sich über 2 Sekunden nach oben bewegt
        button1.startAnimationAsync(anim2) // 2.Führen Sie eine Animation aus, die sich über 2 Sekunden nach unten bewegt
    }
}

Es ist mein erstes Mal, dass ich Kotlin richtig benutze, also kann ich es vielleicht noch verbessern. .. Bitte weisen Sie auf einen guten Code hin.

Für die Implementierung in Kotlin habe ich auf die folgende Site verwiesen

Sie können es übrigens auch mit C # machen

C # (dh Xamarin.Android) kann auch mit einer Kombination aus "async / await (dh Task)" und "TaskCompletionSource" erreicht werden.

C # verfügt auch über eine Erweiterungsmethode, die wie folgt definiert werden kann:

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; //Vergessen Sie nicht, sich abzumelden
            source.SetResult(true); //Kotlin Fortsetzung.resume(Unit)Toko
        };
        anim.AnimationEnd += handler; //Abonnieren Sie die Veranstaltung

        view.StartAnimation(anim);
        return source.Task;
    }
}

Dies ist die Startseite. Fügen Sie beim Aufrufen das Schlüsselwort await hinzu und fügen Sie der Methode, die es enthält, das Schlüsselwort async hinzu (hier OnCreate).

protected async override void OnCreate(Bundle savedInstanceState)
{
    /*Kürzung*/

    while (true)
    {
        await button1.StartAnimationAsync(anim1);
        await button1.StartAnimationAsync(anim2);
    }
}

Es wäre schön, wenn Kotlin im selben Projekt mit Java gemischt werden könnte.

Recommended Posts

Eine Geschichte, die es Kotlin bequem machte, dass es mühsam ist, Animationen kontinuierlich auf Android auszuführen
Suchen Sie einen geeigneten Wert für eine Methode und machen Sie sie zu einem ValueObject
[Docker] Ist es gut genug, um es als mehrstufigen Build zu bezeichnen? → Die Geschichte, die so gut wurde
Ich habe ein Plug-In erstellt, das Jextract mit Gradle-Aufgaben ausführt
Eine Geschichte, die es so einfach wie möglich machte, den Vorgang beim automatischen Erstellen eines PR für Bibliotheksaktualisierungen mit Github Dependabot zu überprüfen
Eine Geschichte, die ich mit Java nur schwer herausfordern konnte
Die Geschichte, ein Projekt zu bauen, das Maven mit Ant gebaut hat
Wenn Sie sshpass von Java mit Shell usw. aufrufen, scheint es notwendig zu sein, einen Pfad zu haben.
Erstellt eine Bibliothek, die die Handhabung von freigegebenen Android-Einstellungen erleichtert
Ich habe mit Vue.js eine Seite erstellt, die Informationen zur Zuckereinschränkung zusammenfasst
Ich habe eine Janken App mit Kotlin gemacht
Ich habe eine Taschenrechner-App für Android erstellt
Ich habe eine Janken App mit Android gemacht
Was zu tun ist, wenn es ungültig ist, weil es nicht mit einem '-' beginnt