Sviluppare un Gioco per Android – Lezione 10: Utilizzare Font Bitmap Android Blog Italia.
Tutto ciò di cui abbiamo bisogno è una sola immagine contente tutti i caratteri di cui abbiamo bisogno e, per semplicità, utilizzeremo un font a spaziatura fissa, ossia con i caratteri della stessa larghezza. Una semplice mappa di caratteri potrebbe essere la seguente:
A questo punto, la semplicità nell’utilizzare font bitmap è evidente. I caratteri sono disposti a griglia, ognuno di questi è alto 12 pixel e largo 8, naturalmente vi è un po’ di spazio tra una riga e l’altra. Una volta sapute queste informazioni, grazie alle lezioni precedenti, dovreste sapere tutti come tagliare i singoli caratteri.
Come potete vedere dall’immagine in alto tratta da Photoshop, i caratteri sono sempre organizzati in celle con una dimensione ben precisa, dunque il lavoro da fare non sarà poi tanto difficile, basterà un semplice ciclo per ritagliare ogni singolo carattere. Possiamo utilizzare, naturalmente, ogni font bitmap che desideriamo. A questo punto, vediamo come lavorare sul codice.
Creiamo il progetto
L’idea sulla quale ci baseremo è quella di utilizzare un metodo, drawString(), passando come parametri la tela sulla quale disegneremo, la posizione (quindi le coordinate x e y) e la stringa da visualizzare. A questo punto, possiamo creare un semplice progetto Android che utilizza un oggetto canvas 2D e implementiamo, come sempre, SurfaceView. Nelle risorse avremo il seguente file che fungerà da alfabeto per le nostre stringhe (sempre in /res/drawable-mdpi).
La classe che andremo a creare la chiameremo DrawingPanel.java e potete vederla qui di seguito:
public class DrawingPanel extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = DrawingPanel.class.getSimpleName(); private Canvas canvas; // la tela per disegnare private Glyphs glyphs; // i caratteri public DrawingPanel(Context context) { super(context); getHolder().addCallback(this); // Inizialliziamo le risorse loadResources(); setFocusable(true); } private void loadResources() { this.glyphs = new Glyphs(BitmapFactory.decodeResource(getResources(), R.drawable.glyphs_green)); Log.d(TAG, "Green glyphs loaded"); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } @Override public boolean onTouchEvent(MotionEvent event) { // disegnare testo al tocco try { canvas = getHolder().lockCanvas(); synchronized (getHolder()) { if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { canvas.drawColor(Color.BLACK); // disegna i caratteri glyphs.drawString(canvas, "Drawing string at " + (int) event.getX() + " " + (int) event.getY(), (int) event.getX(), (int) event.getY()); } if (event.getAction() == MotionEvent.ACTION_UP) { canvas.drawColor(Color.BLACK); glyphs.drawString(canvas, "Drawn string at " + (int) event.getX() + " " + (int) event.getY(), (int) event.getX(), (int) event.getY()); } } } finally { if (canvas != null) { getHolder().unlockCanvasAndPost(canvas); } } return true; } @Override protected void onDraw(Canvas canvas) { } }
Come potete vedere, non c’è bisogno di implementare tutti imetodi per il nostro scopo. Utilizziamo l’oggetto canvas per disegnare la nostra stringa ad ogni tocco, quindi prestate maggiore attenzione a onTouchEvent(). Ogni volta che tocchiamo il display cerchiamo di entrare in possesso della tela per disegnare la stringa e, con il tocco prolungato (ACTION_MOVE), noterete cambiare leggermente il testo.
Infine, liberiamo la tela. Assicuratevi di inserire return true per segnalare che l’evento è stato gestito senza problemi. A questo punto, diamo un’occhiata alla classe più interessante: Glyphs.java. Come avete visto, ne viene creata un’istanza nel metodo loadResources() e, come parametro, le passiamo l’immagine inserita prima nelle risorse. Essa detiene l’associazione tra caratteri e immagini, vediamo come.
La classe Glyphs.java
public class Glyphs { private static final String TAG = Glyphs.class.getSimpleName(); private Bitmap bitmap; // bitmap contenente la mappa di caratteri // Mappa per associare ogni carattere alla bitmap private Map<Character, Bitmap> glyphs = new HashMap<Character, Bitmap>(62); private int width; // larghezza di ogni carattere in pixel private int height; // altezza di ogni carattere in pixel // I caratteri private char[] charactersL = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; private char[] charactersU = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; private char[] numbers = new char[] { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' }; public Glyphs(Bitmap bitmap) { super(); this.bitmap = bitmap; this.width = 8; this.height = 12; // ritagliamo i caratteri // iniziamo dalla prima riga - Caratteri minuscoli for (int i = 0; i < 26; i++) { glyphs.put(charactersL[i], Bitmap.createBitmap(bitmap, 0 + (i * width), 0, width, height)); } Log.d(TAG, "Lowercases initialised"); // Continuiamo con la seconda riga - Caratteri maiuscoli // Notare che la seconda riga inizia più in basso di 15 pixel for (int i = 0; i < 26; i++) { glyphs.put(charactersU[i], Bitmap.createBitmap(bitmap, 0 + (i * width), 15, width, height)); } // riga 3 per i numeri Log.d(TAG, "Uppercases initialised"); for (int i = 0; i < 10; i++) { glyphs.put(numbers[i], Bitmap.createBitmap(bitmap, 0 + (i * width), 30, width, height)); } Log.d(TAG, "Numbers initialised"); // TODO - riga 4 per la punteggiatura } public Bitmap getBitmap() { return bitmap; } public void drawString(Canvas canvas, String text, int x, int y) { if (canvas == null) { Log.d(TAG, "Canvas is null"); } for (int i = 0; i < text.length(); i++) { Character ch = text.charAt(i); if (glyphs.get(ch) != null) { canvas.drawBitmap(glyphs.get(ch), x + (i * width), y, null); } } } }
Al rigo 7 istanziamo l’oggetto di tipo Map che ci servirà ad associare la bitmap ad ogni carattere. Per questa funzione, tuttavia, abbiamo bisogno delle bitmap, ma anche di un array che contenga tutti i caratteri che abbiamo nella nostra immagine. Per comodità, ne abbiamo creati tre: charactersL per le lettere minuscole, charactersU per le maiuscole e numbers per i numeri. Per quanto riguarda la punteggiatura, invece, potete provare ad implementarla voi stessi.
Si noti che l’ordine dei caratteri è lo stesso di quello che troviamo nell’immagine caricata. Successivamente, utilizziamo il metodo put() per associare ad ogni elemento dell’array l’immagine bitmap ritagliata con le giuste dimensioni. Ritaglio e associazione sono le attività più importanti del costruttore.
Infine, abbiamo il metodo con il quale abbiamo iniziato questa decima lezione: drawString(). Esso scorre ogni carattere del testo disegnando la relativa immagine associata ad ogni carattere.
Infine, ecco la consueta classe entry point MainActivity.java, che a questo punto dovreste conoscere molto bene:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(new DrawingPanel(this)); } }
Una volta avviata l’applicazione, dovreste avere un risultato molto simile al seguente:
Sviluppare un Gioco per Android – Lezione 10: Utilizzare Font Bitmap Android Blog Italia.