Um dos recursos mais poderosos e
fascinantes no desenvolvimento utilizando o sistema android é a possibilidade
de poder interceptar eventos na tela com o toque do dedo, o “TouchScreen”. Temos
classes específicas para este trabalho, a minha idéia neste mês é descrever as
principais funcionalidades destas classes junto com seus métodos criando
exemplos didáticos e de grande utilidade no dia-a-dia.
Eventos de Entrada (“Input Events”)
Existem várias maneiras de interceptar
os eventos de interação do usuário com o aplicativo. Ao considerar eventos
dentro de sua interface de usuário, a abordagem é capturar os eventos dentro da
região denominada “View”, fornecendo os meios para fazê-lo. Quando compomos um
layout, fazemos o uso de quantas “Views” forem necessárias, neste caso, podemos
observar vários métodos de retorno de chamada pública que parecem úteis para os
denominados eventos de InPut(entrada) e OutPut(saída). Esses métodos são
chamados pelo Android quando a respectiva ação ocorre no objeto em questão. Por
exemplo, quando um componente (um botão) é tocado, o método “onTouchEvent()” é acionado
no objeto. No entanto, a fim de interceptar isso, você deve estender a classe e
substituir o método. No entanto, ampliando cada objeto “View”, a fim de lidar
com um evento como esse não seria prático. É por isso que a classe “View”
também contém uma coleção de interfaces aninhadas com retornos de chamada que poderemos
utilizar com uma maior facilidade. Estas interfaces, chamadas de “Listeners” (“ouvintes”),
são o seu “bilhete” para capturar a interação do usuário com a interface do
aplicativo. Temos a possibilidade de estender uma
classe “View”, a fim de construir por exemplo um componente personalizado. Outra
situação é estender a classe “Button” para fazer algo mais sofisticado. Neste
caso, poderemos definir os comportamentos de eventos padrão para sua classe
usando os manipuladores de eventos, os (“Event Handlers”)
Manipuladores de Eventos (“Event Handlers”)
De acordo com a própria documentação
do Android, quando estamos construindo um componente a partir da classe “View”
teremos vários métodos para serem implementados, sendo:
onKeyDown (int, KeyEvent) - Chamado quando apertamos alguma tecla.
onKeyUp (int, KeyEvent) - Chamado quando soltamos alguma tecla.
onTrackballEvent (MotionEvent) - Chamado quando ocorre um evento de movimento.
onTouchEvent (MotionEvent) - Chamado quando ocorre um evento de movimento da tela com o toque do dedo.
onFocusChanged (boolean, int, Rect) - Chamado quando recebemos ou perdemos o foco.
onKeyUp (int, KeyEvent) - Chamado quando soltamos alguma tecla.
onTrackballEvent (MotionEvent) - Chamado quando ocorre um evento de movimento.
onTouchEvent (MotionEvent) - Chamado quando ocorre um evento de movimento da tela com o toque do dedo.
onFocusChanged (boolean, int, Rect) - Chamado quando recebemos ou perdemos o foco.
Demonstrei os métodos acima a fim de
apresentar os manipuladores existentes. Daremos importância ao evento
“OnTouchEvent”.
Entendendo a classe “MotionEvent”
A classe
base para suporte TouchScreen é a classe “MotionEvent” onde
é passado para as “Views” através do método onTouchEvent
() (abordado anteriormente) podendo também ser sobrecarregado .
Vejamos na Imagem 01 a hierarquia desta classe para maiores informações.
Figura 01: Estrutura da classe “MotionEvent”.
A
classe “MotionEvent” contém inúmeros métodos e constantes como por
exemplo: informações das coordenadas X, Y e capturas de movimentos.
Principais métodos e constantes
- GetAction(): Este método recebe a ação que foi
executada, fornecendo as seguintes constantes para determinar a ação.
ACTION_DOWN: Ação que ocorre quando um toque foi
iniciado contendo o local de partida inicial do movimento.
ACTION_UP: Esta constante é acionada quando um
gesto pressionado tenha terminado, contendo a localização final, bem como todos
os pontos intermediários desde o último movimento.
ACTION_MOVE: Ação que ocorre entre as constantes
ACTION_DOWN e ACTION_UP. (A movimentação em si)
Todas as
constantes abordadas acima retornam um valor inteiro.
- GetY(): Este
método retorna um valor do tipo “Float” das coordenadas “Y” (linha vertical).
Este valor pode ser transformado para inteiro.
- GetX():Este
método retorna um valor do tipo “Float” das coordenadas “X” (Linha horizontal).
Este valor pode ser transformado para inteiro.
Exemplo 1 - Movimentando uma Imagem com o
toque do dedo
Nos exemplos
deste artigo iremos envolver todos os conceitos aprendidos anteriormente sendo
que neste primeiro criaremos uma imagem dinamicamente. Esta imagem será
movimentada com o dedo e usando o “TouchScreen” na tela do dispositivo. Para
isto descreverei todos os passos daqui pra frente.
Inicie uma aplicação do Zero clicando em “File/New/Android Project...” criando uma classe para estender (extends) para a interface “View”. Clique sobre o pacote e com o botão direito escolha “New/Class”. É nesta classe onde criaremos todos os métodos responsáveis pela movimentação da Imagem em questão. Ver Figura 02.

Figura 02: Criando a classe “CriarImagem.java”.
Inicie uma aplicação do Zero clicando em “File/New/Android Project...” criando uma classe para estender (extends) para a interface “View”. Clique sobre o pacote e com o botão direito escolha “New/Class”. É nesta classe onde criaremos todos os métodos responsáveis pela movimentação da Imagem em questão. Ver Figura 02.

Como foi discutido anteriormente,
devemos utilizar a classe “View” para implementarmos o método OnTouchEvent().
Classe “CriarImagem.java”
Antes de iniciarmos a codificação
desta classe será necessário adicionar uma imagem qualquer em nosso aplicativo.
Basta copiar e colar no diretório “res/drawable-hdpi”. Ver Imagem 03.
Figura 03: Imagem adicionada no
projeto.
Observação Importante:
Esta imagem deverá ser do tipo “.png” ou “jpg” possuindo o nome escrito especificamente em caixa baixa para assim evitar problemas de compilação.
Logo em seguida importaremos as
bibliotecas que serão utilizadas ao decorrer do desenvolvimento.
package pct.Android_OnTouchEvent;
import android.content.Context;
import android.graphics.Canvas;
import
android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class CriarImagem extends View
{
private Drawable imagem;
private int x, y, largura, altura;
private boolean Clicou;
public
int movimento
= 12;
A classe principal “CriarImagem” herdará da classe “View”. Utilizaremos algumas variáveis privadas, sendo uma do tipo “Drawable” responsável por trabalhar com a imagem, outras do tipo “int” onde definimos a largura, altura, as coordenadas X, Y e uma booleana indicando se clicamos ou não na imagem.
public CriarImagem(Context
context, AttributeSet attrs)
{
super(context, attrs);
imagem = context.getResources().getDrawable(R.drawable.theclub);
largura = imagem.getIntrinsicWidth();
altura = imagem.getIntrinsicHeight();
x = 150;
y = 300;
setFocusable(true);
}
No método Construtor
passamos dois parâmetros: o “Context” o Contexto da aplicação e o “AttributeSet”
que significa uma coleção de atributos que podem ser utilizados dentro deste
método. O método
“context.getResources().getDrawable()” irá recuperar a imagem, os métodos “getIntrinsicWidth()”
e “getIntrinsicHeight()” irão retornar a largura e altura respectivamente, x e
y serão as coordenadas para posicionamento da imagem em relação a tela do
dispositivo. Já o método “setFocusable()” definirá se a “view” irá ou não
receber o foco enquanto estiver em modo “TouchScreen”. Deixaremos como “true”
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
imagem.setBounds(x,y,x+largura,y+altura);
imagem.draw(canvas);
}
Para
desenhar a imagem foi necessário reescrever o método “OnDraw()” tendo como
parâmetro a classe “Canvas”. Passamos as coordenadas X e Y e a largura e altura
utilizando o método “setBounds()” e redesenhamos com o “draw()” usando a classe
“Canvas”. Este método é disparado sempre quando necessitamos redesenhar a
imagem.
public boolean onTouchEvent(MotionEvent
motionEvent)
{
this.x = (int)motionEvent.getX();
this.y = (int) motionEvent.getY();
switch(motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
{
Clicou = imagem.copyBounds().contains(x,y);
break;
}
case MotionEvent.ACTION_MOVE:
if (Clicou)
{
this.x = x - (largura/2);
this.y = y - (altura/2);
break;
}
case MotionEvent.ACTION_UP :
{
Clicou = false;
break;
}
}
invalidate();
return true;
}
Este é o principal evento que iremos
trabalhar. Ele tem como parâmetro de entrada a classe “MotionEvent” e retorna
um valor booleano. No primeiro momento iremos atribuir às variáveis globais X e
Y as respectivas coordenadas com os métodos “getX()” e “getY()”. Faremos um
“Case” para comparar as Constantes do método “GetAction()”, o mesmo que recebe a ação que foi executada, fornecendo constantes para
determinar a ação. Na constante “ACTION_DOWN” com o método “copyBounds()”
indicamos que clicamos na imagem informando suas coordenadas. A constante “ACTION_MOVE”,
faz o ato de mover em si, movimentamos a figura fazendo o cálculo das
coordenadas menos o tamanho dividido por dois, dando uma impressão de
movimento. Por final retiramos o foco com a constante “ACTION_UP”. Resumindo,
este método irá movimentar a Imagem conforme o toque do dedo.
Configurações no “AndroidManifest.xml”
Nas configurações do arquivo
“AndroidManifest.xml” não faremos praticamente nada de mirabolante, apenas
setamos o uso da “Activity” “Android_OnTouchEventActivity”
que será comentado logo a seguir. Ver em seguida a listagem completa.
<?xml version="1.0"
encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pct.Android_OnTouchEvent"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Android_OnTouchEventActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Configurações no “Strings.xml”
Este
arquivo irá definir algumas constantes que serão abordadas ao decorrer do
projeto, como por exemplo: a cor cinza que preencherá o fundo onde
movimentaremos a imagem. Ver código abaixo:.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Trabalhando com o evento OnTouchEvent!</string>
<string name="app_name">The Club - Android</string>
<color name="cinza">#D0D0D0</color>
</resources>
Criando o “Lay-Out”
O aplicativo
possuirá um “LinearLayout” onde conterá um “TextView” e um componente chamado
desenho que faz referência à classe “CriarImagem”. Ver Imagem 04.
Figura 04:
Componentes utilizados.
A Imagem 05
nos dá uma noção do Lay-out.
Figura 05: Lay-Out
do exemplo 1.
O XML
correspondente:
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<pct.Android_OnTouchEvent.CriarImagem
android:id="@+id/desenho"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/cinza"
/>
</LinearLayout>
Devemos dar
uma atenção especial na linha de código abaixo:
<pct.Android_OnTouchEvent.CriarImagem />
Percebam que interessante, conseguimos chamar diretamente uma classe (no caso uma “View”) de dentro do XML, é fantástico!
Codificando o exemplo 1
Seguindo a lógica, a atividade “Android_OnTouchEventActivity” que codificaremos a seguir, possuirá
uma chamada para o lay-out “criarimagem.xml” que dentro do mesmo teremos a
classe “CriarImagem.java”, na qual está localizada toda a codificação de nosso
exemplo.
package pct.Android_OnTouchEvent;
import android.app.Activity;
import android.os.Bundle;
public class
Android_OnTouchEventActivity extends Activity
{
@Override
public void onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.criarimagem);
}
}
O “SetContentView()” será
o método que irá chamar a tela de nosso aplicativo. Ver Imagem 06.
Exemplo em “Run-Time”
Figura 06:
Movimentando a Imagem “The Club”.
Exemplo 2 – Pintando e escrevendo na Tela com
o toque do dedo
Este segundo exemplo irá pintar e
desenhar na tela de nosso aplicativo com o toque do dedo. Aprenderemos também a
trabalhar com a classe “Paint”, “Path” entre outras. Os passos são idênticos ao
do exemplo anterior, por isto detalharei um pouco menos para ficar menos
cansativo abordando apenas os conceitos inéditos.
Chega de conversa e vamos ao trabalho!
Classe “PintarTela.java”
Utilizaremos algumas bibliotecas
adicionais para desenvolver este exemplo, veja abaixo:
package pct.Android_OnTouchEvent;
package pct.Android_OnTouchEvent;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import
android.view.View;
Temos a classe “android.graphics.Paint”
sendo específica para pintura, estilo, cor. Ela também oferece base para
desenhar geometrias, texto e bitmaps. Já a classe “android.graphics.Path”
permite realizar contornos e formas geométricas como: segmentos de linhas
retas, curvas quadráticas e cúbicas.
public class PintarTela extends View
{
private Paint paint = new Paint();
private Path path = new Path();
Esta
classe também herdará da classe “View” e utilizará dois objetos, do tipo
“Paint” e “Path”.
public
PintarTela(Context context, AttributeSet attrs)
{
super(context, attrs);
paint.setAntiAlias(true);
paint.setStrokeWidth(6);
paint.setColor(Color.BLUE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
}
Temos o
método “setAntiAlias()” que serve para suavizar as
bordas de nosso toque, o “setStrokeWidh()” é o tamanho da linha, o
“setColor()” para definir a cor, o “setStyle()” o estilo e o “setStrokeJoin()”
é um tratamento específico para quando as linhas se juntarem.
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawPath(path, paint);
}
Método que
irá desenhar usando as configurações definidas anteriormente na classe “Paint”.
@Override
public boolean onTouchEvent(MotionEvent motionEvent)
{
float eventX = motionEvent.getX();
float eventY = motionEvent.getY();
switch (motionEvent.getAction())
{
case MotionEvent.ACTION_DOWN:
path.moveTo(eventX, eventY);
return true;
case MotionEvent.ACTION_MOVE:
path.lineTo(eventX, eventY);
break;
default:
return false;
}
invalidate();
return true;
}
Usaremos apenas as constantes “ACTON_DOWN”
para dar início do movimento de acordo com as coordenadas definidas fazendo o
uso do método “MoveTo()” e a “ACTION_MOVE”para adicionar uma linha a partir do último
ponto especificado pelas coordenadas (x, y).
Configurações no “AndroidManifest.xml”
Adicionaremos
algumas configurações básicas neste arquivo já comentado mais acima, veja o
trecho:
...
<activity android:name=".Android_OnTouchEventActivity_2"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
...
Criando o
“Lay-Out”
Teremos um
“LinearLayout” onde conterá um “TextView” e um componente chamado desenho que
faz referência à classe “Pintartela”. Ver Imagem 07.
Figura 07: Lay-Out
do exemplo 2.
O XML
correspondente:
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<pct.Android_OnTouchEvent.PintarTela
android:id="@+id/desenho"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Codificando o Exemplo 2
Seguindo os passos que já foram
descritos acima foi necessário criar uma classe estendendo de uma “Activity”
para invocarmos o XML contendo a classe “PintarTela”. O método “SetContentView()” irá chamar a tela de nosso aplicativo.
Ver Imagem 08.
Abaixo código completo.
package pct.Android_OnTouchEvent;
import android.app.Activity;
import android.os.Bundle;
public class
Android_OnTouchEventActivity_2 extends Activity
{
@Override
public void onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.pintartela);
}
}
Exemplo em “Run-Time”
Figura 08: Desenhando e Pintando em “Run-Time”.
Referências
http://developer.android.com/reference/android/view/MotionEvent.html
http://developer.android.com/reference/android/view/View.html
http://developer.android.com/reference/android/view/View.html
Conclusões
Uma das
formas de interceptar os eventos de interação do usuário com o aplicativo é
capturar estes eventos dentro de uma região chamada “View”. É a partir desta
classe que discorremos o artigo deste mês. Trabalhamos com o evento
“OnTouchEvent()”, que é o evento que capta o toque do dedo na tela do
dispositivo e a classe “MotionEvent”, classe base para suporte para esta tarefa
junto com métodos e constantes. No primeiro exemplo procurei demonstrar como
movimentar uma imagem com o “TouchScreen”, já no segundo como pintar e escrever
na tela do aplicativo. Esta é uma das inúmeras formas de usar os recursos
“TouchScreen” na programação Android.
Espero que tenham gostado! Deixo aqui um abraço e nos vemos no mês que vem!
Espero que tenham gostado! Deixo aqui um abraço e nos vemos no mês que vem!