Naučte sa vyvíjať Android aplikácie – animácia II

0

Jednu z hlavných nevýhod klasickej animácie by ste objavili, keby ste chceli snímať dotyky na pohybujúci sa objekt, napríklad by ste takto ťukaním prstom chceli zostreľovať objekty. Neuspeli by ste, nakoľko počas animácie sa len priebežne vykresľuje posun z pôvodnej pozície do novej. Skutočné miesto, kde môžete kliknúť na objekt sa nezmení, takže by ste museli implementovať vlastnú logiku na ovládanie dotykom. Oveľa flexibilnejšia je animácia typu Property Animation a umožňuje animovať prakticky akýkoľvek objekt

Fungovanie animácie vysvetľuje jej názov. Animácia zavolá setter objektu a nastaví mu novú hodnotu zvoleného parametra získanú interpoláciou.

Môžete definovať nasledujúce vlastnosti animácie: 

Doba trvania - môžete zadať dobu trvania animácie. Predvolená dĺžka je 300 ms. 

Čas interpolácie-  môžete definovať, akým spôsobom budú hodnoty parametra vypočítavané. Algoritmus výpočtu musíte navrhnúť ako funkciu, kde vstupnou veličinou je aktuálne uplynutý čas a výsledná hodnota je v intervale 0 - 1, teda matematicky zapísané y = f(t), y<0;1> Funkcie môžu byť lineárne aj nelineárne. 

Správanie a počet opakovaní  - môžete určiť, či sa animácia bude, alebo nebude opakovať, keď dosiahne koniec a ak áno, tak koľkokrát. Môžete tiež určiť, či chcete animáciu prehrať v opačnom smere. 

Zoskupovanie – môžete zoskupiť animácie do logických množín, ktoré sú spúšťané spoločne alebo postupne, alebo po uplynutí zadanej oneskorenia. 

Oneskorenie obnovovania - môžete určiť, ako často sa bude aktualizovať zobrazenie. Implicitne je nastavená aktualizácia každých 10 ms, ale rýchlosť, s akou vaše aplikácia dokáže aktualizovať zobrazenie v konečnom dôsledku závisí na tom, ako rýchlo dokáže zariadenie pracovať, čiže ako rýchlo jeho systém môže obsluhovať základný časovač.

PropertyAnimation funguje na štyroch pilieroch

  • ValueAnimator je v princípe časovač, ktorý „tiká“ s nastavenou frekvenciou
  • TimeInterpolator  vypočítava hodnotu parametra podľa vstupného parametra času y = f(t), y<0;1>
  • TypeEvaluator mapuje výsledok z interpolátora na rozsah animácie, matematicky vyjadrené X0 + t *(x1 –x0). Ak je v priebehu potrebné meniť hodnotu parametra napríklad v rozsahu od 200 do 600, evaluator mapuje hodnoty z intervalu <0,1> na hodnoty v interval <200, 600>
  • AnimatorUpdateListener – volá sa pri každej zmene zobrazenia v dôsledku animácie.

S objektom manipuluje trieda ObjectAnimator, odvodená od triedy ValueAnimator Typicky sa volá nad objektom odvodeným od View. K dispozícii sú metódy setRotationX(), setRotationY(), setTranslationX(),setTranslationY(), setScaleX(), setScaleY() a setAlpha().  Všimnite si, že rotovať je možné podľa osi X aj Y, čo znamená že PropertyAnimation nás posúva z 2D do 3D.

Príklad na ilustráciu princípu fungovania Property Animation

Najskôr ukážeme najjednoduchší príklad, v ktorom pomocou animácie zmeníme farbu pozadia objektu ImageView. Rovnako dobre by poslúžil príklad na zmenu iného parametra, napríklad veľkosti objektu, no pre ilustráciu fungovania objekty TypeEvaluator bude lepšie, ak ukážeme zmenu farby ako komplexnejšieho parametra, než je jednoduchá zmena veľkosti. V XML kóde layoutu hlavnej aktivity je len prvok ImageView a tlačidlo na spustenie animácie

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
 
    <ImageView
        android:id="@+id/image_view1"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:contentDescription="popis" />
 
    <Button
        android:id="@+id/start_button"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:padding="30dp"
        android:text="Start"/>
 
</LinearLayout>

Celé dejstvo sa odohráva v obsluhe udalosti zatlačenia tlačidla, ktorým používateľ spustí animáciu. Vytvoríme objekt ValueAnimator, ktorého úlohou bude meniť hodnotu farby zo žltej na zelenú. Mapovanie zmeny hodnoty kódu farby definujeme pomocou objektu TypeEvaluator, v tomto prípade nakoľko sa jedná o ARGB hodnotu, využije sa ArgbEvaluator.

ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(),        Color.YELLOW, Color.GREEN);

Evaluátor v tomto prípade nemôže urobiť lineárne mapovanie, nakoľko hexadecimálne hodnoty priradené použitým farbám sú

Color.YELLOW = #ffff00

Color.GREEN = #00ff00

Ak by interpolátor začal hodnotu mapovať lineárne, začala by sa prejavovať modrá zložka farby, nakoľko pozície farebných zložiek  RGB v hexadecimálnej konštante čísla farby je #RRGGBB

V listeneri, ktorý sa volá pri každej zmene animácie je možné realizovať nejakú akciu. V našom príklade pre ilustráciu fungovania nastavíme pre ImageView novú hodnota pozadia.

Kompletný kód hlavnej aktivity

package com.example.animacia3;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
 
public class MainActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState)    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startButton = (Button) findViewById(R.id.start_button);
        startButton.setOnClickListener(new View.OnClickListener()              {
            @Override
            public void onClick(View v) {
                spustAnimaciu();
            }
        });
    }
 
    public void spustAnimaciu() {
        final ImageView imageView = (ImageView) findViewById(R.id.image_view1);
        ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(),
                Color.YELLOW, Color.GREEN);
 
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                imageView.setBackgroundColor((Integer) animation
                        .getAnimatedValue());
            }
        });
        anim.setDuration(3000);
        anim.start();
    }
}

Príklad  komplexnejšieho využitia Property Animation

Tento príklad ukáže, ako je možné vytvoriť postupnosť na seba nadväzujúcich rôznych typov animácií. Aby ste mali možnosť porovnávať, v nasledujúcom príklade využitia Property Animation  bude podobná animácia ako v stati Príklad Tween animácie, teda znižovanie priesvitnosti, pohyb objektu a zmenu jeho veľkosti. Pre posun objektu je metodické a účelné definovať rozmer posunutia v resourceoch v súbore  dimens.xml

<resources>
    <dimen name="posun">200dp</dimen>
</resources>

Obrázok, ktorý bude predmetom animácie umiestnite do zložky drawable. V našom príklade je to súbor et.png.

Návrhový XML kód hlavnej aktivity aplikácie obsahuje iba jeden prvok typu ImageView

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
    <ImageView
        android:id="@+id/obrazok"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:src="@drawable/figurka"
        android:alpha="0"
        android:contentDescription="figúrka"/>
</RelativeLayout>

Animácia sa spustí automaticky v obsluhe udalosti onWindowFocusChanged() kedy sa spustí prvá úloha ako objekt Runnble. V našom prípade je to zmena priesvitnosti, teda zmena parametra Alpha. Po jej ukončení sa prostredníctvom metódy withEndAction() spustí ďalšia úloha, v tomto prípade rotácia obrázka.

Runnable prihladnost = new Runnable() 
{
   public void run() 
   {
      iv.animate().setDuration(2000)
                   .setInterpolator(new LinearInterpolator()).alpha(1.0f)
                   .withEndAction(rotace);
   }
  };

Rotácia rovnakým mechanizmom spustí ďalšiu časť animácie – posun.

Kompletný kód hlavnej aktivity

package com.example.animacia4;
 
import androidx.appcompat.app.AppCompatActivity;
 
import android.os.Bundle;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.ImageView;
 
public class MainActivity extends AppCompatActivity {
 
    private ImageView iv;
    @Override
    public void onCreate(Bundle savedInstanceState)  {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
 
    @Override
    public void onWindowFocusChanged(boolean hasFocus)  {
        super.onWindowFocusChanged(hasFocus);
        iv = (ImageView) findViewById(R.id.obrazok);
        if (hasFocus) priehladnost.run();
    }
 
    Runnable priehladnost = new Runnable() {
        public void run() {
            iv.animate().setDuration(2000)
                    .setInterpolator(new LinearInterpolator()).alpha(1.0f)
                    .withEndAction(rotacia);
        }
    };
 
    Runnable rotacia = new Runnable() {
        public void run() {
            iv.animate().setDuration(3000)
                    .setInterpolator(new AccelerateInterpolator())
                    .rotationBy(1080.0f).withEndAction(posun);
        }
    };
 
    Runnable posun = new Runnable() {
        public void run()  {
            float transl = getResources().getDimension(R.dimen.posun);
            iv.animate().setDuration(2000)
                    .setInterpolator(new OvershootInterpolator())
                    .translationXBy(transl).translationYBy(transl)
                    .withEndAction(zvetsenie);
        }
    };
 
    Runnable zvetsenie = new Runnable() {
        public void run()  {
            iv.animate().setDuration(2000)
                    .setInterpolator(new AnticipateInterpolator())
                    .scaleXBy(1.0f).scaleYBy(1.0f);
        }
    };
}

Screenshoty z animácie

 

Rekapitulácia seriálu

1  – Prvá aplikácia 

2 – Možnosti emulátorov 

3 - Zorientujte sa v projekte aplikácie

4 – Princípy dizajnu a škálovania

5 – Uporiadanie prvkov používateľského rozhrania

6 – Obsluha udalostí

7 – Aplikácia s dvomi aktivitami  

8 – Spustenie na reálnom zariadení

9 – Intenty, alebo kto to urobí

10 – Dotyky a gestá

11 - Dotyky a gestá II  

12  - Zmena orientácie displeja

13 – Grafika 1

14 – Grafika II

15 - Animácia

Luboslav Lacko

Všetky autorove články

Pridať komentár

Mohlo by vás zaujímať

Mohlo by vás zaujímať