Live Wallpaper, ou Papel de Parede Animado conforme a tradução, foram introduzidos na versão 2.1 (API 7) do Android. Como o nome sugere, ele nada mais é do que um fundo que se mexe. Mas ao contrário do que se imagina ele pode ser muito mais poderoso do que se imagina. É possível fazer praticamente qualquer coisa que um aplicativo comum faz, inclusive interagir com toques do usuário.
Mas, como dizia Tio Ben, com grandes poderes vêm grandes responsabilidades. Lembre-se que o Live Wallpaper irá rodar boa parte do tempo, então este não deve fazer muitas operações pesadas para não consumir muitos dados ou energia do aparelho.
O exemplo mostrado aqui pode ser baixado clicando aqui.
O Live Wallpaper não passa de um Service que rodará infinitamente enquanto você manter o Live Wallpaper. Então vamos começar definindo isso no AndroidManifest:
<uses-feature android:name="android.software.live_wallpaper" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <service android:label="@string/app_name" android:name=".ExempleWallpaper" android:permission="android.permission.BIND_WALLPAPER"> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <meta-data android:name="android.service.wallpaper" android:resource="@xml/wall" /> </service> </application>
Note o uses-feature que é necessário e a definição do Service. Assim como na definição de um app widget aqui também definimos um meta-data que está em xml/wall. Vamos cria-lo:
<?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"/>
Só isso. Dentro dessa tag poderíamos definir android:settingsActivity que seria a Activity de configuração, semelhante a Activity de configuração do app widget, mas por enquanto não iremos fazer isso. A seguir vamos criar nosso service ExempleWallpaper propriamente dito, como definido no Manifest:
package com.gdacarv.tutoriandroid.livewallpaper; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.os.Handler; import android.service.wallpaper.WallpaperService; import android.view.MotionEvent; import android.view.SurfaceHolder; public class ExempleWallpaper extends WallpaperService { // Handler utilizado para redesenhar a tela private final Handler mHandler = new Handler(); @Override public Engine onCreateEngine() { return new ExempleEngine(); } class ExempleEngine extends Engine { // Frames Por Segundo private static final int FPS = 30; // Velocidade da animação private static final float SPEED = 3; // Utilizado quando a tela é movida private float mOffset; // Registra toques na tela private float mTouchX = -1; private float mTouchY = -1; private int height, width; private Bitmap mBitmap; private float x,y; private int dirHorizontal = 1, dirVertical = 1; private final Runnable mDrawCube = new Runnable() { public void run() { drawFrame(); } }; private boolean mVisible; @Override public void onCreate(SurfaceHolder surfaceHolder) { super.onCreate(surfaceHolder); mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); //setTouchEventsEnabled(true); // Ativa eventos de toque (Atualmente desativados por default) } @Override public void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mDrawCube); } @Override public void onVisibilityChanged(boolean visible) { mVisible = visible; if (visible) { drawFrame(); } else { mHandler.removeCallbacks(mDrawCube); } } @Override public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) { super.onSurfaceChanged(holder, format, width, height); // Salva largura e altura da tela this.width = width; this.height = height; } @Override public void onSurfaceCreated(SurfaceHolder holder) { super.onSurfaceCreated(holder); } @Override public void onSurfaceDestroyed(SurfaceHolder holder) { super.onSurfaceDestroyed(holder); mVisible = false; mHandler.removeCallbacks(mDrawCube); } @Override public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) { mOffset = xOffset; } @Override public void onTouchEvent(MotionEvent event) { // Guarda toques na tela. Só é executado se comando setTouchEventsEnabled(true) for executado previamente. if (event.getAction() == MotionEvent.ACTION_MOVE) { mTouchX = event.getX(); mTouchY = event.getY(); } else { mTouchX = -1; mTouchY = -1; } super.onTouchEvent(event); } void drawFrame() { final SurfaceHolder holder = getSurfaceHolder(); Canvas c = null; try { c = holder.lockCanvas(); if (c != null) { mover(); onDraw(c); } } finally { if (c != null) holder.unlockCanvasAndPost(c); } // Agenda proximo re-desenho mHandler.removeCallbacks(mDrawCube); if (mVisible) { mHandler.postDelayed(mDrawCube, 1000 / FPS); } } private void mover() { // Move a imagem x += SPEED*dirHorizontal; y += SPEED*dirVertical; if(y < 0 || y > height-mBitmap.getHeight()) dirVertical *= -1; if(x < 0 || x > width-mBitmap.getWidth()) dirHorizontal *= -1; } private void onDraw(Canvas c) { // Limpa tela e desenha a imagem c.drawARGB(255, 0, 0, 0); c.drawBitmap(mBitmap, x, y, null); } } }
O que importa nesse Service é a Engine. Estendemos a classe Engine para que possamos definir nossos próprios métodos. Note que Engine fornece métodos de criação, de alteração da Surface, de mudança (deslizamento) de tela, de toque na tela, entre outros. Você deve sempre fazer algo no onVisibilityChanged para que quando o wallpaper não estiver visível ele pause o seu funcionamento, assim economizando recursos.
Acesse a documentação oficial e esse exemplo para mais informações.
3 comentários:
E para usar um arquivo *swf ao invés de *bmp, qual o procedimento?
@Heráclito: Creio que não seja possível usar swf em Live Wallpapers, talvez seja possível usar num aplicativo com WebView.
Gustavo, descobrir seu blog hoje.
Na moral, seu blog e muito bom. E o melhor VC responde as duvidas de todos, muito bom mesmo.
Todos esses scripts são java? Como postei antes aguardo resposta sobre movimentos touch.
Eu estava fazendo meus experimentos com unity e parei por não conseguir esses scripts.
Tenho um xperia mini pro e consegui movimentos através do teclado físico, e não ficou legal.
Se eu conseguir, vou retornar os testes. Vlw
Postar um comentário