Problem mit for-Schleife, delay und Margins

N

no1Ltan

Fortgeschrittenes Mitglied
Threadstarter
Hi Leute,

ich würde gerne folgendes realisieren:
Bei einem Klick auf einen Button, der sich innerhalb eines ConstraintLayouts befindet,
soll dessen Position verschoben werden.
Um es wie eine Art Effekt aussehen zu lassen, soll die Position mehrmals verschoben werden.

Ich habe es so, wie in dem Code unten, probiert.
Es gibt allerdings gleich 2 Probleme/Unklarheiten:

Problem 1)
Der Delay funktioniert anscheinend nur 1x.
Beim Klick auf den Button wird dessen Position nach 500 ms verschoben.
Danach passiert nichts mehr.
Ich hatte eigentlich erwartet, dass zwischen den einzelnen for-loops je 500 ms Pause sind.
Die Log zeigt mir, dass die for-Schleife 10x durchgelaufen ist - allerdings nur mit 1x 500 ms Pause.

Natürlich hatte ich statt x++ auch x = x + 20 probiert, um die Unterschiede deutlich sichtbar zu machen.

Problem 2)
Ich habe die x-Variable im Programmkopf mit dem Wert 200 initialisiert.
In meinem Beispiel hier funktioniert es zwar, aber in Echt müsste der tatsächliche Wert,
der sich innerhalb der lp-Variable befindet, incrementiert werden.
Wie soll das aber gehen?
In der lp müssten sich ja 4 Werte befinden: Left, Top, Right, Bottom.
Heißt also, statt x++ müsste ich eher mit "top++" arbeiten, was so nicht funktionieren würde.
Code:
for (int i = 1; i <= 10; i++) // 10 loops
        {
            final Handler handler = new Handler();
            handler.postDelayed(new Runnable()
            {
                @Override
                public void run()
                {
                    x++; // Increment x by 1
                    ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) button1.getLayoutParams(); // Get current margins of button 1
                    lp.setMargins(0, x, 0, 0); // Write margin values inside of lp variable (L, T, R, B)
                    button1.setLayoutParams(lp); // Change margin of button1
                    Log.wtf("x ist:", String.valueOf(x)); // Show current value of x in Log - LOG IS OK!
                }
            }, 500); // 500 ms delay
Danke für jede Hilfe!
 
D

deek

Stammgast
Punkt 1:
Deine for Schleife läuft ja quasi sofort durch. Das heißt du erzeugst 10 runnables, die nach 500ms getriggert werden. Also werden 500ms nach dem ersten SChleifendurchlauf alle 10 runnables (+der Zeit, die ein Schleifendurchlauf dauert, aber das ist marginal) gestartet, damit geht das so schnell, dass du nur den letzten positionswechsel siehst.
Möchtest du das so machen musst du entweder deine 500 ms mit i malnehmen beim posten oder in den runnalbe selbst am Ende ein neues Runnable posten.

Punkt 2:
So sollte man das nicht machen, dafür kann man einen ObjectAnimator nehmen:
Move a View with Animation  |  Android Developers
 
N

no1Ltan

Fortgeschrittenes Mitglied
Threadstarter
Hallo deek,

Punkt 1:
Muss ich mir genauer anschauen.
Das, was du schreibst, ergibt für mich auf jeden Fall schon mal Sinn.

Punkt 2:
Super, dann brauche ich das Rad ja nicht neu erfinden :)
Habe es jetzt so hier gemacht, und es entspricht in der Tat meinen Vorstellungen!

Code:
     oa = ObjectAnimator.ofFloat(button1, "translationX", 30f, 0f); // Move object 30px to right, then back to 0
     oa.setDuration(100); // 100 ms animation duration
     oa.setRepeatCount(3); // Repeat animation 3 times
     oa.start(); // Start animation!
Soweit ich es verstanden habe arbeitet der ObjectAnimator relativ, also heißt 0f Ausgangsposition,
nicht Absolutwert: 0 Pixel.
30f, 0f -> Verschiebe Object AB HIER um 30px nach rechts, dann wieder zurück auf die Ursprungsposition.

P.S. Im Programmkopf hab ich natürlich den ObjectAnimator (oa) deklariert.

Vielen Dank!
-- Dieser Beitrag wurde automatisch mit dem folgenden Beitrag zusammengeführt --
Hallo,

ich muss leider nochmal was fragen.

Bei mehreren Buttons habe ich es jetzt so gemacht, dass alle Buttons eine Methode aufrufen,
die für die Animation zuständig ist und "sich selbst schicken".
(Ist sicherlich die bessere Variante statt den Codeblock x mal zu kopieren und einzufügen.)

Das hier funktioniert einwandfrei:
Code:
.
.
.
ObjectAnimator oa; // Access variable for ObjectAnimator
.
.
.
        button1.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                animationEffect(button1); // Run animation method for this button
            }
        });
        button2.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                animationEffect(button2); // Run animation method for this button
            }
        });
.
.
.
    public void animationEffect(Button o) // Animation effect for selected object
    {
        oa = ObjectAnimator.ofFloat(o, "translationX", 30f, 0f); // Move object 30px to right, then back to 0
        oa.setDuration(100); // 100 ms animation duration
        oa.setRepeatCount(1); // Repeat animation 3 times
        oa.start(); // Start animation!
    }
Das Problem ist jedoch, dass ich das nur für Buttons nutzen kann.
Wenn ich z.B. bei einer klickbaren TextView den Effekt hinzufügen will, wird es nicht gehen.
Code:
        textViewBlue.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                animationEffect(textViewBlue); // Hier erwartet die Methode einen Button
            }
        });
Bei animationEffect((Button)textViewBlue); verschwindet zwar die Warnung, aber die App stürzt ab, sobald ich auf die tv klicke.

Muss ich für jeden klickbaren Objekttypen eine separate Methode erzeugen, oder kann ich statt:
Button o
auch einfach sowas wie:
Object o
machen?
(Object o hat nicht funktioniert)

P.S. Butterknife habe ich nicht vergessen, es steht noch auf meiner ToDo-Liste ;)
 
D

deek

Stammgast
animationEffect(View view) sollte gehen.
Du kannst hatl eine TextView nicht zu einem Button casten. Aber ein Object ist zu allgemeint für ObjectAnimator nehme ich an.
 
N

no1Ltan

Fortgeschrittenes Mitglied
Threadstarter
Hat geklappt - Super.
Danke nochmals!
 
Oben Unten