sexta-feira, 25 de maio de 2012

Criando animação quadro a quadro com AnimationDrawable

( Android ) 


Neste tutorial vou demonstrar como é fácil criar uma animação Quadro a Quadro utilizando a classe AnimationDrawable. 


A maneira mais simples de criar uma animação quadro a quadro é definir a animação em um arquivo XML, colocado no res/drawable, e defini-la como background de um objeto View. No nosso caso será um objeto ImageView. 


Então chega de papo e vamos lá !!! 


Crie um novo projeto Android no Eclipse. 


Eu vou chama-lo de Exemplo Animation.  


print do projeto: 


Antes de proseguir, baixe as imagens que serão utilizadas no exemplo, e salve-as nas pastas res/drawable-hdpi , drawable-ldpi , drawable-mdpi. 
download: www.theheadsman.com.br/imagens_anima.zip


O próximo passo será criar o arquivo XML. 


Para criar o XML, selecione a pasta RES do projeto, clique com o botão direito, depois NEW  /  OTHER... / PASTA ANDROID.  Na tela de dilalogo selecione ANDROID XML FILE e aperte o botão NEXT.


print  tela de dialog:



na próxima tela: 


Resource Type: drawable
File: O nome do XML
Root Element: animation-list
Clique em finish e pronto. 


Observe que foi criada uma nova pasta chamada drawable sem as definições de DPIs. 

print XML




Um AnimationDrawable definido no XML consiste de uma único  elemento <animation-list>, e uma série de tags <item> aninhadas. 


Segue o XML: 


<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:drawable="@drawable/anima1" android:duration="100" />
    <item android:drawable="@drawable/anima2" android:duration="100" />
    <item android:drawable="@drawable/anima4" android:duration="100" />
    <item android:drawable="@drawable/anima6" android:duration="100" />
    <item android:drawable="@drawable/anima8" android:duration="100" />
    <item android:drawable="@drawable/anima9" android:duration="100" />
    <item android:drawable="@drawable/anima10" android:duration="100" />
    <item android:drawable="@drawable/anima11" android:duration="100" />
    <item android:drawable="@drawable/anima12" android:duration="100" />
    <item android:drawable="@drawable/anima13" android:duration="100" />
    <item android:drawable="@drawable/anima14" android:duration="100" />
    <item android:drawable="@drawable/anima15" android:duration="100" />
    <item android:drawable="@drawable/anima16" android:duration="100" />
</animation-list>


android:drawable="" carrega as imagens que foram salvas anteriormente nas pastas drawable. 

android:duration=" - define o tempo de cada frame em milisegundos.

O nosso XML animation-list está configurado, agora vamos criar o componente ImageView onde serão carregadas as imagens da animação.  


res/layout/main.xml  


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

    <ImageView
        android:id="@+id/animacao"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:layout_gravity="center_horizontal"/>

</LinearLayout>



E por fim, na nossa activity: 



public class ExemploAnimation extends Activity {

private ImageView animaHorse;

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

// Carrega o ImageView e define o background para o nosso XML
// AnimationDrawable

animaHorse = (ImageView) findViewById(R.id.animacao);
animaHorse.setBackgroundResource(R.drawable.animation);

AnimationDrawable frameAnimaHorse = (AnimationDrawable) animaHorse.getBackground();

// Inicia a animação

frameAnimaHorse.start();

}
}



Rode a aplicação. 


Obs: Teste em um aparelho real, a animação não está rodando com o virtual device.


O play da animação é um loop por padão 


Mas se quiser que a animação rode uma vez e pare, utilize o método setOneShot() da classe AnimationDrawable.  Por padrão o método setOnShot() recebe false como parâmetro. Passe true para que rode uma vez. 


frameAnimaHorse.setOneShot(true);


Faça um teste:
Crie um botão e chame o método stop() no objeto de instancia frameAnimaHorse.

frameAnimaHorse.stop();


O método IsRunning() indica se a animação está sendo executada ou não - retorna um valor boleano.



Pesquise mais sobre a API.
http://developer.android.com/reference/packages.html


Valeu, fui !!!


quarta-feira, 16 de maio de 2012

Convertendo pixels em dp e vice-versa

( Android )


Eu tive alguns problemas com o tamanho dos objetos customizados no android utilizando a API do Java em telas com densidades diferentes, e vou demonstrar como resolver esse problema, uma vez que o Java utiliza pixels como unidade de medida e não dp.  Mas antes vou falar um pouco de tamanho de tela (screen size). 


Essa medida refere-se ao tamanho físico da tela, medida na diagonal.  O  Android atualmente separa os tamanhos físicos de tela em quatro diferentes categorias, que são:  tela pequena small, tela normal normal, tela grande large, tela extragrande xlarge. 


Vou dar um exemplo mais claro de cada nomenclatura com aparelhos reais. 


small:  Sony Ericsson, Xperia Mini,  que possuem uma pequena tela QVGA de 240 x 320 pixels 


normal: HTC G1, HTC Magic , Motorola DEXT, possuem uma tela HVGA média 320 x 480 pixels. Nesse grupo também se encontram os celulares um pouco maiores como o Nexus One, Sony  Xperia X10, Mororola Milestone, Samsung Galaxy S, que possuem telas WVGA que varia entre 480 x 800 e 480 x 854 pixels. 


large: O tablet Samsung Galaxy Tab de 7", que possui tela WVGA de 1024 x 600 pixels 


xlarge: Os novos tablets com Andoids 3.x, com tela WXGA de 1280 x 800 pixels 




Obs: Essas medidas de tela são aproximadas e podem ter variações. 


A resolução da tela é expressa em pixels, por exemplo, 320 x 480 px. Diferente do Iphone, no Android temos diversos celulares ,com  resoluções diferentes, o que torna a vida do desenvolvedor android mais emocionante  ( Risos ).  Assim, no desenvolvimento dos aplicativos devemos evitar utilizar essa notação para definir os tamanhos das views, valores de margens, espaçamentos e qualquer outro parâmetro. No Android nunca trabalhamos diretamente com pixels, e sim com dp (density-independent pixel). 


Densidade da tela é basicamente a relação entre a quantidade de pixels existentes na tela com a sua largura e altura. Quanto maior a densidade, maior será a quantidade de pixels espalhados pela tela. 


Bem, agora é fácil, é só eu usar dp ao invés de px que todos os meus problemas estão resolvidos. 


Mas e se você criar uma view customizada com o Canvas ao invés do xml por exemplo ? 


Como eu havia explicado anteriormente, o Java utiliza a notação de pixels para definir valores. 




Então chega de falar e vamos ao código. 


Digamos que estamos criando uma view customizada e precisamos desenhar um quadrado na tela. Para isso precisamos utilizar a API de desenho. Vamos lá. 


1 - Crie um projeto android no eclipse. 


2 - Crie uma classe TesteView para API de desenho. 




print do projeto. 




O código da Activity é simples, vamos apenas alterar o setContentView(); 


public class ExemploConverPixelDP extends Activity {
    

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new TesteView(this));
    }
    
   
    
}

Segue o código da classe TesteView. 

public class TesteView extends View {



private Paint paint;



public TesteView(Context context) {

super(context);



paint = new Paint();



paint.setColor(Color.LTGRAY);
paint.setStyle(Style.FILL);

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

canvas.drawRect(0, 0, 320 / 2, 480 / 2, paint);

}

}

Rode e veja o resultado. 



Nós sabemos que existem telas HVGA de 320 x 480 pixels e, portanto o quadrado vai ocupar a metade do tamanho da tela. Mas o que acontece se executarmos o mesmo exemplo em uma tela de maior densidade, como uma WVGA de 480 x 800 pixels. 


Segue o print do exemplo executado no virtual divice com a tela HVGA de 320 x 480 pixels a esquerda, e a direita a tela WVGA de 480 x 800 pixels. 




Como podemos verificar, na tela HVGA, o exemplo funcionou como o esperado, e nosso quadrado que (na verdade é um retângulo) preenche exatamente a metade da tela. Isso porque colocamos o valor fixo em pixels no método de desenho.  Mas ao executarmos o mesmo exemplo em um aparelho de densidade mais alta o resultado foi diferente. O "quadrado" foi reduzido, pois a quantidade de pixels é maior nessa tela. E agora, o que fazemos ? 


A solução é pensar que esses valores de 320 x 480 pixels na verdade estão em dp ( density-independent pixel) e fazer a conversão do valor de dp para pixels.  Se fosse um arquivo XML de layout bastava colocar a notação em (dp) que tudo ficava lindo, mas em Java teremos que fazer a conversão manualmente. 


Método que converte os valores: 



public float toPixel(Context context, float dip) {
Resources r = context.getResources();
float densidade = r.getDisplayMetrics().density;
int px = (int) (dip * densidade + 0.5f);
return px;
}


Segue o código completo: 




public class TesteView extends View {

private Paint paint;

public TesteView(Context context) {
super(context);

paint = new Paint();

paint.setColor(Color.LTGRAY);
paint.setStyle(Style.FILL);

}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

// valores em dp
float larguraDP = 320;
float alturaDP = 480;

// convertendo para pixels
float larguraPX = toPixel(getContext(), larguraDP);
float alturaPX = toPixel(getContext(), alturaDP);

// desenha o quadrado
canvas.drawRect(0, 0, larguraPX / 2, alturaPX / 2, paint);

}

// converte de DP para Pixels
public float toPixel(Context context, float dip) {
Resources r = context.getResources();
float densidade = r.getDisplayMetrics().density;

int px = (int) (dip * densidade + 0.5f);
return px;
}

}



Agora rode e olhe o resultado. 


O nosso quadrado (retângulo) agora ocupa o mesmo espaço, nas duas talas com diferentes densidades. 


print do virtual device:  





 Eu esqueci de mencionar !!! 


tela QVGA retorna a densidade de 0.75 
tela HVGA retorna a densidade de 1.0 
tela WVGA retorna a densidade de 1.5




 Problema resolvido.  




Até mais ! 






domingo, 13 de maio de 2012

Tela Splash Screen

( Android ) 


Vocês já devem ter visto alguma aplicação abrindo uma tela inicial com uma mensagem "Por favor aguarde"ou uma imagem , como por exemplo, a tela de jogo Angry Birds e a tela de iniciação do próprio eclipse. Essas telas são Splash Screens e para implementá-las no Android podemos utilizar um handler. 


Uma tela splash screen deve permanecer aberta por um determinado tempo para que a aplicação consiga realizar algum processo inicial. 


Esse tipo de funcionalidade impressiona o usuário, dando uma impressão de que a aplicação é bem robusta e profissional. 


Vamos criar uma simples Activity que exibirá uma imagem na tela, a qual ficará aberta por 3 segundos. 


Então vamos lá. 


Para começar, crie um projeto android no eclipse.  


Print do projeto: 




A seguir, vamos configurar o nosso arquivo de layout. A configuração é bem simples, uma vez que vamos apenas abrir uma imagem na Tela Splash Screen. 


Salve a imagem na pasta res/drawable do projeto. 


Em seguida, crie um novo arquivo  de layout com o nome de splashscreen.xml e insira a tag do componente ImagView com as seguintes configurações: 


     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:src="@drawable/bgpeixes"   <!- Imagem -->
     android:layout_gravity="center"

Imagem utilizada no exemplo: 




Segue o arquivo completo.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical" >


    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center"
        android:src="@drawable/bgpeixes" />

</LinearLayout>




Agora crie a activity  SplashScreen. 

Esta é a classe que envia um java.lang.Runnable para ser processado com atraso de 3 segundos. 



public class SplashScreen extends Activity implements Runnable {

private final int DELAY = 3000;

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

Handler h = new Handler();
h.postDelayed(this, DELAY);

}

public void run() {

startActivity(new Intent(this, Main.class));

finish();

}

}



O exemplo tem uma simples activity que mostra uma imagem na tela, Enquanto isso um handler foi criado, e o método postDelayd(Runnable,delayMillis) foi utilizado para agendar um java.lang.Runnable com atraso de 3 segundos.

Importante: Configure a SpashScreen para a primeira activity da aplicação, que está configurada com a acão MAIN e categoria LAUNCHER no AndroidManifest.xml. 

Para melhorar o visual da sua aplicação, vamos retirar a barra de titulo da activity. 

No AndroidManifest.xml na tag activity insira o seguinte código: android:theme="@android:style/Theme.Black.NoTitleBar"

       <activity 
            android:name=".Main"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Black.NoTitleBar">
        </activity>

Faça o mesmo para a Activity SplashScreen. 

Rode a aplicação, e aí está a sua Splash Screen. 

Até mais !





quinta-feira, 10 de maio de 2012

Criando a tela principal - Dashboard

( Android )


No google I/O 2011 foram apresentadas diversas palestras sobre android, e o Google criou um aplicativo demonstrando algumas boas práticas no desenvolvimento de aplicação mobile para Android. 


Essa aplicação se chama iosched e pode se encontrada no site http://code.google.com/p/iosched 


Uma das funcionalidades que essa aplicação demonstra é o padrão dashboard para a tela inicial, onde temos o menu da aplicação. Felizmente o Google liberou o código-fonte da classe DashboardLayout, que pode ser encontrada neste link: 


http://iosched.googlecode.com/hg//android/src/com/google/android/apps/iosched/ui/widget/DashboardLayout.java


Obs: É a mesma classe utilizada pelo google para criar a tela principal do app Google+ p/ Android


É, eu sei. Essa url é ridiculamente grande.   A classe está escondida nas profundezas dos servidores do Google.  Rsrsrsrsrs 


Essa classe é um gerador de layout customizado que vai organizar as views - neste caso, botões - da tela principal em linhas e colunas. 


Beleza, agora que você já baixou a classe DashboardLayout.java, vamos criar o projeto. Meu objetivo não é ensinar como usar o eclipse, então eu parto do pré-suposto que todos saibam criar um projeto Android no mesmo.   Pode dar o nome que preferir ao projeto. 


Print  do projeto criado: 



Vamos copiar essa classe para nosso projeto, inserindo-a no pacote com.google.android.apps.iosched.ui.widget  A única alteração que vamos fazer no código-fonte  é configurar o números de colunas para 2.


Para isso, encontre o seguinte trecho de código na classe DashboardLayout:   int cols = 1;  , altere o valor de cols para 2. 




Print - pacote com.google.android.apps.iosched.ui.widget  com a classe DashboardLayout inserida: 




O próximo passo é customizar o arquivo /res/layout/main.xml para utilizar o DashboardLayout. Felizmente esse layout é mágico e vai fazer todo o trabalho pessado. Rsrsrsrsrs 


Podem fazer o download das imagens utilizadas no exemplo: 
http://www.theheadsman.com.br/exemploblog.zip


Segue o código: 


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

    <include layout="@layout/include_header" />

    <com.google.android.apps.iosched.ui.widget.DashboardLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_weight="1" >

        <Button
            android:id="@+id/bt1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/btn1"
            android:drawablePadding="10dp" />

        <Button
            android:id="@+id/bt2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/btn2"
            android:drawablePadding="10dp" />

        <Button
            android:id="@+id/bt3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/btn3"
            android:drawablePadding="10dp" />

        <Button
            android:id="@+id/bt4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/btn4"
            android:drawablePadding="10dp" />
        
    </com.google.android.apps.iosched.ui.widget.DashboardLayout>

    <include layout="@layout/include_footer" />

</LinearLayout>


Note que quando criamos a tag do DashboardLayout utilizamos o nome completo da classe, pois ela é uma View customizada. 

com.google.android.apps.iosched.ui.widget.DashboardLayout

( Futuramente estarei falando de Views customizadas ). 

Print do main.xml 



O Arquivo /res/layout/main.xml representa o menu principal com o dashboard e possui os quatros botões da aplicação.  Note que no meu layout eu incluir outros dois arquivos para criar o cabeçalho e o rodapé. (Fica a critério de vocês a forma como vão configurar os seus projetos) 


É para fechar, vamos adicionar eventos aos botões. 

Voltado a classe principal do projeto, Main.java.

O que precisamos implementar agora são os eventos dos botões. Para isso vamos alterar o código-fonte da classe Main conforme demonstrado a seguir. ( Que no meu caso está com o nome de ExemploDashboard ).


public class ExemploDashboard extends Activity implements OnClickListener {

private Button bt1;
private Button bt2;
private Button bt3;
private Button bt4;

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

bt1 = (Button) findViewById(R.id.bt1);
bt1.setOnClickListener(this);
bt2 = (Button) findViewById(R.id.bt2);
bt2.setOnClickListener(this);
bt3 = (Button) findViewById(R.id.bt3);
bt3.setOnClickListener(this);
bt4 = (Button) findViewById(R.id.bt4);
bt4.setOnClickListener(this);
}

public void onClick(View v) {

if (v == bt1) {

/* Implemente você */

} else if (v == bt2) {

/* Implemente você */

} else if (v == bt3) {

/* Implemente você */

} else if (v == bt4) {

/* Implemente você */

}

}
}




 Por hoje é só pessoal !