sábado, 2 de abril de 2011

Animações no Android (2)

Olá povo,

Nesse post vou mostrar como utilizar algumas animações prontas que o Android disponibiliza em sua API no pacote android.view.animation. Começe criando um novo projeto e deixe o seu arquivo de layout conforme abaixo:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<Spinner
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/spnAnimation"/>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Play"/>

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="fill">

<ImageView
android:layout_width="wrap_content"
android:id="@+id/imageView1"
android:layout_height="wrap_content"
android:src="@drawable/icon"/>
</FrameLayout>
</LinearLayout>


Nosso arquivo de layout é bem simples. Ele consta de um Spinner (combobox) que vai listar as animações disponíveis na API. Em seguida temos um botão que iniciará a animação. Logo abaixo, temos uma ImageView dentro de um FrameLayout, utilizamos esse layout pois uma das animações permite que posicionemos uma View em uma posição absoluta da tela (X e Y). Mas você pode estar se perguntando: se vai usar posição absoluta, porque não usar o AbsoluteLayout?
O AbsoluteLayout é considerado obsoleto (deprecated) uma vez que podemos utilizar o FrameLayout que faz a mesma função, só que ao invés de usarmos as propriedades layout_x e layout_y, utilizamos layout_marginLeft e layout_marginTop respectivamente.

Explicado o layout, vamos agora ao código que reliza as animações. Abra a activity da aplicação e deixe-a de acordo com a classe abaixo:


public class ExemploAnimationActivity
extends Activity
implements OnClickListener, AnimationListener {

private Spinner spnAnimation;
private ImageView imgView;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

String[] animations = {
"Alpha", "Rotate", "Scale", "Translate"};

ArrayAdapter<String> adapter =
new ArrayAdapter<String>(
this,
android.R.layout.simple_spinner_item,
animations);
spnAnimation =
(Spinner)findViewById(R.id.spnAnimation);
spnAnimation.setAdapter(adapter);

findViewById(R.id.button1).
setOnClickListener(this);

imgView =
(ImageView)findViewById(R.id.imageView1);
}

@Override
public void onClick(View v) {
Animation animation = null;
Interpolator interpolator = null;

switch (spnAnimation.getSelectedItemPosition()) {
case 0: // Alpha
animation = new AlphaAnimation(1, 0);
break;

case 1: // Rotate
interpolator = new OvershootInterpolator(2);
animation = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
animation.setRepeatCount(3);
break;

case 2: // Scale
interpolator = new AccelerateInterpolator(4);
animation = new ScaleAnimation(
1, 3, 1, 3,
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 0);
break;

case 3: // Translate
interpolator = new BounceInterpolator();
animation = new TranslateAnimation(
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 200,
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 200);
}
animation.setInterpolator(interpolator);
animation.setAnimationListener(this);
animation.setDuration(3000);
imgView.setAnimation(animation);
animation.start();
}

@Override
public void onAnimationEnd(Animation animation) {

switch (spnAnimation.getSelectedItemPosition()) {
case 0: // Alpha
animation = new AlphaAnimation(0, 1);
break;

case 1: // Rotate
return;

case 2: // Scale
animation = new ScaleAnimation(3, 1, 3, 1);
break;

case 3: // Translate
animation = new TranslateAnimation(
Animation.ABSOLUTE, 200,
Animation.ABSOLUTE, 0,
Animation.ABSOLUTE, 200,
Animation.ABSOLUTE, 0);
}
animation.setDuration(3000);
imgView.setAnimation(animation);
animation.start();
}

@Override
public void onAnimationRepeat(Animation animation) { }

@Override
public void onAnimationStart(Animation animation) {}
}


Nossa classe implementa as interfaces OnClickListener e OnAnimationListener, a primeira nós já conhecemos, a segunda serve para notificar das mudanças de estado da animação. Com ela é possível saber quando a animação começou, terminou e quando foi repetida. Esses método estão declarados no final da nossa classe.
No método onCreate criamos um adapter para preencher nosso spinner com as 4 animações do pacote de animações (existe mais uma que é AnimationSet que não usarei aqui) . Depois setamos o evento de clique do botão e por fim obtemos a referência da ImageView que iremos animar.
No método onClick é que as coisas começam a ficar animadas (entederam o trocadilho? animações no Android... coisas animadas... dãããã... :)

Começamos declarando um obejto Animation que será atribuída mais adiante à nossa ImageView. Logo abaixo, declaramos um Interpolator. Esse objeto (opcional) serve para aplicar um efeito mais legal à nossa animação.

A instrução switch inicializa a animação de acordo com a opção selecionada no Spinner. A primeira opção cria um AlphaAnimation que recebe como parâmetros a transparência inicial e final (1 quer dizer opaco, 0 transparente). Nesse caso, essa animação fará a ImageView desaparecer completamente.
A segunda opção cria uma RotateAnimation que fará a View girar. Os parâmetros são o ângulo inicial e final, e uma posição X e Y para servir de eixo para a rotação. No nosso exemplo passamos uma posição relativa à imagem (RELATIVE_TO_SELF) baseada na metade do seu tamanho (0.5). Para essa animação criamos um interpolator que faz com que a animação faça um efeito antes parar (ficou difícil de explicar esse interpolator - vocês testando é melhor :).
A terceira animação é a ScaleAnimation que fará com que a ImageView aumente de tamanho. Ela recebe como argumento a proporção inicial e final em X, depois a proporção inicial e final em Y, e assim como a RotateAnimation, pede uma âncora para basear o aumento da imagem. No nosso caso colocamos a posição absoluta 0,0... O Interpolator usado aqui fará a animação acelerada.
A última animação é a TranslateAnimation que serve para movimentar a nossa ImageView para uma nova posição X e Y. Aqui informamos que ele deve se movimentar da posição X inicial 0 para 200 final, e Y inicial 0 e final 200. O Interpolator utilizado é o BounceInterpolator que fará o efeito de quicar.
Após iniciar o objeto animation, setamos seu interpolator, sua duração para 3 segundos (3000 milisegundos) e seu listener. Depois associamos a animação à ImageView e mandamos iniciar a animação. Quando a animação terminar, o método onAnimationEnd será chamado e fará a animação ao contrário. Analisem o código baseado na explicação acima que eu acho que vocês vão entender :)

Testem esse exemplo, explorem os Intrpolators com outras animações e não esqueçam de deixar seus comentários.

4br4ç05,
nglauber

7 comentários:

Anônimo disse...

Muito bom Glauber. Sou seu fãn. Amanhã vou compilar no galaxy e comentar melhor.

Abs,.
@SostenesSoares

Bit disse...

Ai meu amigo vc e seus debug is on the table sensacionais! Fiquei curioso e vou testar para ver como posso brincar com esta dica.

vlw
Sandro Marques (Bit)

Marcos Vinicius disse...

É o seguinte Glauber, eu to com um aplicativo pra fazer uma animação tipo do Facebook que mobile. Tem um botão de menu, e quando é clicado o menu aparece a esquerda e dividi a tela com o layout principal e quando o botão é clicado de novo o menu fecha com uma animação do tipo que a tela principal vai cobrindo o menu, como posso fazer isso?

Grato,

Marcos Vinicius disse...

Glauber tenho uma animação pra fazer e é do tipo do facebook mobile, tem um botão menu que quando é clicado o menu aparece na esquerda dividindo a tela com o layout principal como se estivesse empurrado e quando clicado novamente ele fecha e o layout principal tem animação tipo cobrindo o menu.

Nelson Glauber disse...

Oi Marcos,

Não existe um componente nativo do Android para fazer esse tipo de menu. Mas achei esses dois links aqui que podem ajudar:

https://github.com/gitgrimbo/android-sliding-menu-demo

http://stackoverflow.com/questions/11377472/slide-out-menu-like-android-google-and-youtube-style-slide-menu-not-like-faceb

Espero que ajude.

4br4ç05,
nglauber

Unknown disse...

E ai Glauber blz?
Cara estou com um problema q nao consigo resolver de maneira alguma:(
Sei que é algum detalhe no qual eu nao estou conseguindo localiza.
Bom tenho um frame layout com varias views, dai coloco junto uma view com todo preenchimento e relativa ao meu frameLayout, quero usar uma animação para essa view que será um menu quando clicada faça um translate até a direita deixando somente uma aba a mostra, dai quando clicar novamente nessa aba o menu retornar a posiçao inicial.
O meu problema é que quando ocorre esse processo eu perco a posição do onCLick....Espero q tenha entendido e possa me ajuda :D

abss

Nelson Glauber disse...

Oi Luiz,

Esse é realmente um problema do framework de animações do Android 2.x.

Dá uma olhada nesse link.
http://nglauber.blogspot.com.br/2012/04/animacoes-no-android-3.html

4br4ç05,
nglauber