Se ricordo bene, la Bitmap è la tela, il Canvas è l'immagine, il Paint è il pennello.
Provo a buttare giù un codice...
Ecco, per creare la Bitmap, cosa che non ho mai fatto, si usa un codice Bitmap.createBitmap.
In precedenza, ho creato una bitmap da un file, ma potrei anche dover creare una bitmap vuota per disegnarci sopra col canvas. Ecco, appunto:
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888);Il canvas va costruito sulla tela!
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp);Invece il pennello si crea di per sé: il pennello è qualcosa di staccato dall'immagine e dalla tela.
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint();Ora intingiamo il pennello sulla tavolozza:
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.GREEN);E ora possiamo disegnare...
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.GREEN); canvas.drawRect(20, 20,40,20,paint);...e non succede niente!
Ma abbiamo dimenticato di appendere il quadro!
Proviamo...
Per far questo dobbiamo prima identificare la parete, quindi appendere.
Provo a fare così:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/parete"
tools:context="com.example.grafica.MainActivity" >
...identifichiamo quindi lo sfondo:
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.GREEN); canvas.drawRect(20, 20,40,20,paint); RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete);...e ora appendiamo il quadro:
Bitmap bmp= Bitmap.createBitmap(400,400,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.GREEN); canvas.drawRect(20, 20,40,20,paint); RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete); parete.setBackgroundDrawable(new BitmapDrawable(bmp));...e non succede assolutamente nulla!
Forse devo fare la bitmap un po' più grande, come nell'esempio che sto seguendo e interpretando liberamente...
Bitmap bmp= Bitmap.createBitmap(400,800,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.GREEN); canvas.drawRect(50,50,200,200,paint); RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete); parete.setBackgroundDrawable(new BitmapDrawable(bmp));Ecco, sì, ce l'ho fatta!
Se tolgo tutta quella monnezza da studi precedenti, magari si visualizza anche la bitmap minuscola che avevo creato? Proviamo...
Bitmap bmp= Bitmap.createBitmap(100,100,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.GREEN); canvas.drawRect(20, 20,40,20,paint); RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete); parete.setBackgroundDrawable(new BitmapDrawable(bmp));No. E' inutile che incollo un'immagine in cui non c'è nulla.
Dubbio: le dimensioni che ho impostato per il rettangolo sono 200 e 200, ossia doveva venire un quadrato! Perché invece è un rettangolo?
Ho risolto!
Evidentemente è dovuto al fatto che le dimensioni della bitmap vengono modellate sulle dimensioni del RelativeLayout, e quindi vengono "stirate". Forse, ho pensato, la soluzione sta nel creare una bitmap delle stesse dimensioni del Layout, ma come fare a individuarle?
Inizialmente ho trovato la soluzione parete.getWidth() e parete.getHeight(), però non ottenevo risultati: richiedendo il valore di queste grandezze sul LogCat ottenevo valori zero.
Poi ho trovato questa pagina sul mitico StackOverflow e ho risolto: evidentemente le misure del layout vengono prese solo all'evento onWindowFocusChanged.
public void updateSizeInfo(){ RelativeLayout parete=(RelativeLayout)findViewById(R.id.parete); h=parete.getHeight(); w=parete.getWidth(); Bitmap bmp=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); Canvas canvas=new Canvas(bmp); Paint paint=new Paint(); paint.setColor(Color.RED); canvas.drawRect(50,50,200,200,paint); parete.setBackground(new BitmapDrawable(bmp)); } public void onWindowFocusChanged(boolean hasfocus){ updateSizeInfo(); }Sono metodi separati dal metodo OnCreate.
Ottengo un quadrato rosso che resta tale anche orientando l'emulatore in modalità Portrait.
Dunque l'evento onWindowFocusChanged recepisce il cambiamento di visualizzazione?
Vediamo di sperimentarlo...
public void onWindowFocusChanged(boolean hasfocus){ Log.d("EVENTO","ONWINDOWFOCUSCHANGED"); }Ecco il LogCat:
01-04 22:24:14.807: D/EVENTO(4894): ONWINDOWFOCUSCHANGED 01-04 22:25:08.878: D/PAUSE(4894): ONPAUSE 01-04 22:25:08.878: D/STOP(4894): ONSTOP 01-04 22:25:08.928: D/CREATE(4894): ONCREATE 01-04 22:25:08.978: D/START(4894): ONSTART 01-04 22:25:08.978: D/RESUME(4894): ONRESUME 01-04 22:25:09.008: I/Choreographer(4894): Skipped 30 frames! The application may be doing too much work on its main thread. 01-04 22:25:09.038: D/EVENTO(4894): ONWINDOWFOCUSCHANGED 01-04 22:25:25.238: D/PAUSE(4894): ONPAUSE 01-04 22:25:25.238: D/STOP(4894): ONSTOP 01-04 22:25:25.288: D/CREATE(4894): ONCREATE 01-04 22:25:25.358: D/START(4894): ONSTART 01-04 22:25:25.358: D/RESUME(4894): ONRESUME 01-04 22:25:25.378: I/Choreographer(4894): Skipped 34 frames! The application may be doing too much work on its main thread. 01-04 22:25:25.448: D/EVENTO(4894): ONWINDOWFOCUSCHANGED 01-04 22:25:33.199: D/PAUSE(4894): ONPAUSE 01-04 22:25:33.199: D/STOP(4894): ONSTOP 01-04 22:25:33.259: D/CREATE(4894): ONCREATE 01-04 22:25:33.269: D/START(4894): ONSTART 01-04 22:25:33.269: D/RESUME(4894): ONRESUME 01-04 22:25:33.339: D/EVENTO(4894): ONWINDOWFOCUSCHANGEDSì: A ogni movimento dell'emulatore corrisponde un Pause, uno Stop, poi un OnCreate, un OnStart e un OnResume.
Manca OnDestroy, ma mi sono accorto adesso che non avevo messo il codice che ricevesse e mostrasse l'evento.
Lo metto adesso:
@Override protected void onDestroy(){ super.onDestroy(); Log.d("DESTROY","ONDESTROY"); }E riproviamo!
01-04 22:30:11.403: D/EVENTO(4941): ONWINDOWFOCUSCHANGED 01-04 22:30:11.583: I/Choreographer(4941): Skipped 43 frames! The application may be doing too much work on its main thread. 01-04 22:30:11.623: D/gralloc_goldfish(4941): Emulator without GPU emulation detected. 01-04 22:30:11.663: D/PAUSE(4941): ONPAUSE 01-04 22:30:11.663: D/STOP(4941): ONSTOP 01-04 22:30:11.663: D/DESTROY(4941): ONDESTROY 01-04 22:30:11.673: D/CREATE(4941): ONCREATE 01-04 22:30:11.723: D/START(4941): ONSTART 01-04 22:30:11.723: D/RESUME(4941): ONRESUME 01-04 22:30:11.833: D/EVENTO(4941): ONWINDOWFOCUSCHANGED 01-04 22:31:05.364: D/PAUSE(4941): ONPAUSE 01-04 22:31:05.364: D/STOP(4941): ONSTOP 01-04 22:31:05.364: D/DESTROY(4941): ONDESTROY 01-04 22:31:05.364: D/CREATE(4941): ONCREATE 01-04 22:31:05.394: D/START(4941): ONSTART 01-04 22:31:05.394: D/RESUME(4941): ONRESUME 01-04 22:31:05.484: D/EVENTO(4941): ONWINDOWFOCUSCHANGED 01-04 22:31:11.634: D/PAUSE(4941): ONPAUSE 01-04 22:31:11.634: D/STOP(4941): ONSTOP 01-04 22:31:11.634: D/DESTROY(4941): ONDESTROY 01-04 22:31:11.694: D/CREATE(4941): ONCREATE 01-04 22:31:11.764: D/START(4941): ONSTART 01-04 22:31:11.764: D/RESUME(4941): ONRESUME 01-04 22:31:11.784: I/Choreographer(4941): Skipped 38 frames! The application may be doing too much work on its main thread. 01-04 22:31:11.854: D/EVENTO(4941): ONWINDOWFOCUSCHANGEDE infatti...
Okay! Abbiamo risolto!
Adesso, per focalizzare meglio la cosa, rifaccio tutto con una nomenclatura metaforica che aiuti a memorizzare:
public void Disegna(){ Bitmap tela=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); Canvas dipinto=new Canvas(tela); Paint pennello=new Paint(); pennello.setColor(Color.CYAN); dipinto.drawCircle(100, 100, 200, pennello); RelativeLayout muro=(RelativeLayout)findViewById(R.id.muro); muro.setBackground(new BitmapDrawable(tela)); } public void onWindowFocusChanged(boolean hasfocus){ Disegna(); }Un piffero!!! Non ho impostato le variabili w e h ai valori di larghezza e altezza del muro!
Riproviamo...
public void Disegna(){ RelativeLayout muro=(RelativeLayout)findViewById(R.id.muro); w=muro.getWidth(); h=muro.getHeight(); Bitmap tela=Bitmap.createBitmap(w,h,Bitmap.Config.ARGB_8888); Canvas dipinto=new Canvas(tela); Paint pennello=new Paint(); pennello.setColor(Color.CYAN); dipinto.drawCircle(100, 100, 200, pennello); muro.setBackground(new BitmapDrawable(tela)); } public void onWindowFocusChanged(boolean hasfocus){ Disegna(); }Un po' fuori, ma mi sembra un cerchio perfetto!
Nessun commento:
Posta un commento