Skip to main content

UI: Animation – Animacje

Kolejnym tematem, jaki weźmiemy dziś na warsztat, są animacje.
Temat myślę, że ciekawy i wręcz banalny, jeśli chodzi o implementację.

Do stworzenia animacji posłuży nam klasa Animation.

Wstęp

Działanie animacji polega na sekwencyjnym wyświetlaniu klatek, które reprezentują pojedynczy obrazek. Klatki odtwarzane wystarczająco szybko tworzą efekt animacji.

Wykorzystanie

Animację możemy wykorzystać jako wskaźnik postępu podczas wykonywania operacji, które wymagają dłuższej chwili na wykonanie, np.:

  • łączenie się z Internetem,
  • inicjalizacja formularza.

W takim przypadku, jest wręcz naszym obowiązkiem poinformować użytkownika, że aplikacja cały czas wykonuje przewidziane dla niej zadania i się nie zawiesiła.

Uprawnienia

Do wczytywania obrazków potrzebujemy uprawnień Image, które dodajemy do pliku manifest.xml w naszym projekcie.

<?xml version="1.0" encoding="utf-8"?>
<Manifest>
  <Id>93bt1p123e</Id>
  <Secret>9C645DDBA19C71BAD1204DA4DAA7A0B9</Secret>
  <AppVersion>1.0.0</AppVersion>
  <ManifestVersion>1.2</ManifestVersion>
  <Privileges>
    <Privilege>
      <Name>IMAGE</Name>
    </Privilege>
  </Privileges>
  <DeviceProfile>
    <APIVersion>2.0</APIVersion>
  </DeviceProfile>
</Manifest>

Zasoby

Dla celów tego artykułu stworzyłem pięć klatek animacji paska postępu, które wyświetlane będą sekwencyjnie tworząc prostą animację:

Pliki kopiujemy do folderu domowego aplikacji /Home.

Implementacja

#ifndef _FORM1_H_
#define _FORM1_H_

#include <FBase.h>
#include <FUi.h>

#include <FMedia.h>
#include <FGraphics.h>

using namespace Osp::Base;
using namespace Osp::Media;
using namespace Osp::Graphics;

class Form1 :
	public Osp::Ui::Controls::Form,
	public Osp::Ui::IActionEventListener,
	Osp::Ui::IOrientationEventListener
{

// Construction
public:
	Form1(void);
	virtual ~Form1(void);
	bool Initialize(void);

// Implementation
protected:
	static const int ID_BUTTON_ANIMATION = 101;

	Osp::Ui::Controls::Button *__pButtonAnimation;
	Osp::Base::Collection::ArrayList __AnimationFrames;
	Osp::Ui::Controls::Animation * __pAnimation;
	Bitmap* CreateFrame(String fileName, int width, int height);

public:
	virtual result OnInitializing(void);
	virtual result OnTerminating(void);
	virtual void OnActionPerformed(const Osp::Ui::Control& source, int actionId);
	virtual void OnOrientationChanged(const Osp::Ui::Control &source, Osp::Ui::OrientationStatus orientationStatus);
};

#endif	//_FORM1_H_
#include "Form1.h"

using namespace Osp::Base;
using namespace Osp::Ui;
using namespace Osp::Ui::Controls;

Form1::Form1(void)
{
}

Form1::~Form1(void)
{
}

bool
Form1::Initialize()
{
	// Construct an XML form
	Construct(L"IDF_FORM1");

	return true;
}

result
Form1::OnInitializing(void)
{
	result r = E_SUCCESS;

	// TODO: Add your initialization code here

	AddOrientationEventListener(*this);

	// Get a button via resource ID
	__pButtonAnimation = static_cast<Button *>(GetControl(L"IDC_BUTTON_ANIMATION"));
	if (__pButtonAnimation != null)
	{
		__pButtonAnimation->SetActionId(ID_BUTTON_ANIMATION);
		__pButtonAnimation->AddActionEventListener(*this);
	}

	// Wymiary klatki
	int width = 149;
	int height = 38;

	// Wczytujemy obrazki
	Bitmap* pBitmapFrame1 = CreateFrame(L"/Home/frame_1.png", width, height);
	Bitmap* pBitmapFrame2 = CreateFrame(L"/Home/frame_2.png", width, height);
	Bitmap* pBitmapFrame3 = CreateFrame(L"/Home/frame_3.png", width, height);
	Bitmap* pBitmapFrame4 = CreateFrame(L"/Home/frame_4.png", width, height);
	Bitmap* pBitmapFrame5 = CreateFrame(L"/Home/frame_5.png", width, height);

	// Tworzymy klatki animacji
	AnimationFrame* pAnimationFrame1 = new AnimationFrame(*pBitmapFrame1, 1000);
	AnimationFrame* pAnimationFrame2 = new AnimationFrame(*pBitmapFrame2, 1000);
	AnimationFrame* pAnimationFrame3 = new AnimationFrame(*pBitmapFrame3, 1000);
	AnimationFrame* pAnimationFrame4 = new AnimationFrame(*pBitmapFrame4, 1000);
	AnimationFrame* pAnimationFrame5 = new AnimationFrame(*pBitmapFrame5, 1000);

	// Dodajemy klatki animacji do kolekcji
	__AnimationFrames.Construct();
	__AnimationFrames.Add(*pAnimationFrame1);
	__AnimationFrames.Add(*pAnimationFrame2);
	__AnimationFrames.Add(*pAnimationFrame3);
	__AnimationFrames.Add(*pAnimationFrame4);
	__AnimationFrames.Add(*pAnimationFrame5);

	// Tworzenie animacji
	__pAnimation = new Animation();

	// Centrowanie
	int xPos = GetWidth() / 2 - width / 2;

	// Wywołanie konstruktora animacji
	__pAnimation->Construct(Rectangle(xPos, 100, width, height), __AnimationFrames);

	// Ilość powtórzeń animacji
	__pAnimation->SetRepeatCount(1000);

	// Dodanie animacji do formularza
	AddControl(*__pAnimation);

	return r;
}

result
Form1::OnTerminating(void)
{
	result r = E_SUCCESS;

	// TODO: Add your termination code here
	__AnimationFrames.RemoveAll(true);

	return r;
}

void
Form1::OnActionPerformed(const Osp::Ui::Control& source, int actionId)
{
	switch(actionId)
	{
	case ID_BUTTON_ANIMATION:
	{

		if (__pAnimation->GetStatus() == ANIMATION_STOPPED)
		{
			__pButtonAnimation->SetText(L"Stop");
			__pAnimation->Play();
		}
		else
		{
			__pButtonAnimation->SetText(L"Play");
			__pAnimation->Stop();
		}

		break;
	}
	default:
		break;
	}
}

// Zmiana orientacji ekranu - przelicz ponownie współrzędne elementów na formularzu
void Form1::OnOrientationChanged(const Osp::Ui::Control &source, Osp::Ui::OrientationStatus orientationStatus)
{
	Osp::Graphics::Rectangle clientArea = GetClientAreaBounds();

	__pAnimation->SetPosition(clientArea.width / 2 - __pAnimation->GetWidth() / 2, 50);
	__pButtonAnimation->SetPosition(clientArea.width / 2 - __pButtonAnimation->GetWidth() / 2, 120);
}

Bitmap* Form1::CreateFrame(String fileName, int width, int height)
{
	Image pImageFrame;
	pImageFrame.Construct();
	Bitmap* pBitmapFrame = pImageFrame.DecodeN(fileName, BITMAP_PIXEL_FORMAT_RGB565, width, height);
	return pBitmapFrame;
}

Zwalnianie zasobów

Musimy ręcznie zadbać o usuniecie obrazków z kolekcji. Sama klasa Animation zostanie usunięta automatycznie przez formularz, który jest jej rodzicem.

__AnimationFrames.RemoveAll(true);

RemoveAll() przyjmuje jeden argument deallocate. Podanie wartości true oznacza nie tylko usunięcie elementu z kolekcji, ale także zwolnienie pamięci zajmowanej przez ten obiekt.

Opis niektórych metod

Metoda GetStatus() klasy Animation zwraca aktualny status animacji. Lista możliwych stanów:

  • ANIMATION_STOPPED,
  • ANIMATION_PAUSED,
  • ANIMATION_PLAYING.

Wynik działania

[yframe url=’http://www.youtube.com/watch?v=s5XT338ElrI’]

markac

Full-stack Web Developer