Visualizzazione post con etichetta effetti. Mostra tutti i post
Visualizzazione post con etichetta effetti. Mostra tutti i post

Far "pulsare" un'immagine... o qualche altro elemento!

Per far "pulsare" qualche elemento nella propria app sono necessari 3 elementi:
  • l'oggetto da far "pulsare" (ad esempio, un ImageView)
  • l'XML con la configurazione dell'animazione
  • il codice per gestire l'animazione

Oggetto da far "pulsare"

L'oggetto da far pulsare può essere un semplice ImageView, come questo:

1
2
3
4
5
6
<ImageView
    android:id="@+id/ivIconOk"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    app:srcCompat="@drawable/ic_result_ok"
    />

Animare utilizzando un XML

L'XML per l'animazione è il seguente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale xmlns:android="http://schemas.android.com/apk/res/android"
           android:duration="120"
           android:fromXScale="1"
           android:fromYScale="1"
           android:pivotX="50%"
           android:pivotY="50%"
           android:repeatCount="3"
           android:repeatMode="reverse"
           android:toXScale="0.8"
           android:toYScale="0.8"
           android:interpolator="@android:anim/bounce_interpolator"
        />
</set>

Quest'animazione fa pulsare 3 volte l'oggetto (riduce dal 100% al 50% di dimensione, fissando il punto centrale) e poi si ferma.

Alcune annotazioni

Per "pulsazione" si intende riduzione o ingrandimento. Impostarlo a 3 volte vuol dire che, partendo dalla dimensione minore, si ingrandirà, si rimpicciolirà e poi si reingrandirà di nuovo.
Il repeatMode "reverse" indica che, concluso un ciclo, riprende dalla forma corrente (ingrandimento-riduzione-ingrandimento-riduzione...)

Codice Java

Questo invece è il codice per attivare la "pulsazione":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
final ImageView iv = (ImageView) findViewById(R.id.ivIcon);
Animation pulse = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.pulse);

pulse.setAnimationListener(new Animation.AnimationListener()
{
    @Override
    public void onAnimationStart(Animation animation)
    {
        // avvio della pulsazione
    }

    @Override
    public void onAnimationEnd(Animation animation)
    {
        // conclusione dell'animazione
    }

    @Override
    public void onAnimationRepeat(Animation animation)
    {
        // ad ogni ripetizione dell'animazione
    }
});

iv.startAnimation(pulse);

Gestire le animazioni su elementi dentro un ConstraintLayout

Il problema, quando si utilizza un ConstraintLayout, è che il sistema dà la priorità ai "constraint" più che alle specifiche altezze (che non vengono prese in considerazione).

Per gestire delle animazioni (o anche solo per gestire cambi di dimensioni), è necessario utilizzare di ConstraintSet e reimpostarli al bisogno.

Ecco un codice di esempio che gestisce la procedura:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
// button che avvia l'animazione
Button btn = (Button) findViewById(R.id.btnRileva);

// listener per l'attività
btn.setOnClickListener(new View.OnClickListener()
{
    @Override
    public void onClick(final View v)
    {
        // contenitore RelativeLayout
        final RelativeLayout rlContainer = (RelativeLayout) findViewById(R.id.rlContainer);

        // parametri di un ConstraintLayout
        final ConstraintLayout clMain = (ConstraintLayout) findViewById(R.id.ccMainLayout);

        // set di "constraint" (da cambiare o da ripristinare)
        final ConstraintSet set = new ConstraintSet();
        final ConstraintSet original = new ConstraintSet();

        // per avere una copia degli originali, bisogna clonarli
        set.clone(clMain);
        original.clone(clMain);

        // altezza iniziale dell'elemento
        final int initialHeight = rlContainer.getMeasuredHeight();

        // durata dell'effetto
        final int duration = (int)(initialHeight / v.getContext().getResources().getDisplayMetrics().density);

        Animation a = new Animation()
        {
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t)
            {
                // inizio dell'attività di animazione
                if (interpolatedTime == 0)
                {
                    // rottura della connessione del vincolo del contenitore da "animare"
                    set.clear(R.id.rlContainer, ConstraintSet.BOTTOM);

                    // applicazione del set al contenitore "padre" (la root del layout)
                    set.applyTo(clMain);

                    // impostazione dell'altezza iniziale, in modo da non presentare "strane variazioni"
                    rlContainer.getLayoutParams().height = initialHeight;

                    // avverto il sistema che il layout è cambiato, così viene ridisegnato
                    rlContainer.requestLayout();
                }
                // conclusione dell'attività di animazione
                else if(interpolatedTime == 1)
                {
                    // faccio sparire il contenitore
                    rlContainer.setVisibility(View.GONE);
                }
                else
                {
                    // calcolo dell'altezza in base al tempo di interpolazione
                    int height = initialHeight - ((int)(initialHeight * interpolatedTime));

                    // imposto l'altezza
                    rlContainer.getLayoutParams().height = height;

                    // avverto il sistema che il layout è cambiato, così viene ridisegnato
                    rlContainer.requestLayout();
                }
            }

            @Override
            public boolean willChangeBounds()
            {
                return true;
            }
        };

        // imposta la durata dell'animazione
        a.setDuration(duration);

        // imposto un listener per gestire avvio e fine dell'animazione
        a.setAnimationListener(new Animation.AnimationListener()
        {
            @Override
            public void onAnimationStart(Animation animation) { }

            @Override
            public void onAnimationEnd(Animation animation)
            {
                Toast.makeText(getApplicationContext(), "fine dell'animazione", Toast.LENGTH_LONG).show();

                // reimposto il ConstraintSet originale
                original.applyTo(clMain);
                rlContainer.getLayoutParams().height = initialHeight;
                rlContainer.requestLayout();
            }

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

        // avvio l'animazione
        rlContainer.startAnimation(a);
    }
});

Disabilitare "effetto" click in un button, mantenendo e gestendo il click

Per rimuovere l'effetto del "click" (cioè l'ombreggiatura al momento del tocco) in un bottone, bisogna definire il background del bottone con un elemento drawable:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<Button
    android:id="@+id/btnVisualizzaMenuPeso"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/button_peso"
    app:layout_constraintBottom_toTopOf="@+id/llListaPeso"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:background="@drawable/togglebutton_peso_color_background"
    android:textColor="@color/colorTextWhite"
    />

A questo punto si definisce l'elemento @drawable/togglebutton_peso_color_background:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true">
        <shape android:shape="rectangle" >
            <corners android:radius="3dip" />
            <stroke
                android:width="1dip"
                android:color="@android:color/transparent"
                />
            <solid android:color="@color/colorTextWhite" />
            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp"
                />
        </shape>
    </item>
    <item>
        <shape android:shape="rectangle">
            <padding
                android:bottom="10dp"
                android:left="10dp"
                android:right="10dp"
                android:top="10dp"
                />
        </shape>
    </item>
</selector>

In questo modo, quando l'elemento viene "toccato", non visualizza l'ombra o altro.

Generare un colore randomico di tonalità "pastello"

Questo script restituisce il codice di un colore generato a caso nelle tonalità pastello. La generazione viene definita attraverso le 3 ca...