Activitats

Piano infantil

L’objectiu d’aquesta activitat és crear una aplicació orientada als nens petits, on hi hagi un conjunt d’imatges i en clicar sobre cadascuna d’elles es reprodueixi un so diferent i hi hagi una resposta visual mitjançant una animació per interpolació de cada imatge (és a dir, fer que les imatges donin una volta).

Podeu descarregar tot seguit el codi corresponent a aquesta activitat:

Per tal de crear aquesta aplicació cal estructurar la feina a fer: en primer lloc, la disposició (layout) amb les imatges que serviran de tecles, tot seguit s’afegiran les animacions que s’activaran en clicar cada tecla, i finalment s’associarà un fitxer d’àudio a cada tecla per tal que es reprodueixi en prémer-la.

Creació del layout

En primer lloc s’ha de crear una nova aplicació Android obrint l’Android Studio i anant a File/New Project…. Un cop creada, primerament s’han de carregar les imatges que es faran servir com a tecles del piano a la carpeta del projecte /res/drawable/. És molt important que les imatges que s’afegeixen a aquesta carpeta tinguin un nom sense espais, tot en minúscules i sense signes ni accents.

Un cop comprovat això, es poden moure totes les imatges (en aquest exemple en són sis) a la carpeta /res/drawable/ per tal que siguin accessibles per a l’aplicació. A la següent figura es pot veure la carpeta amb les sis imatges carregades.

Figura Carpeta de recursos amb les imatges carregades

A continuació s’ha de crear la disposició d’elements a la pantalla de l’aplicació (layout) per tal de col·locar les imatges en una disposició matricial, en aquest cas amb dues files i tres columnes, per tal de distribuir els sis botons. Per això el layout principal és lineal vertical, i dins seu hi ha dos layouts horitzontals, un per a cada fila d’imatges.

D’altra banda, cada ImageView contindrà una de les imatges que es faran servir. Tots els ImageView comparteixen les mateixes propietats per tal que tinguin les característiques necessàries per a aquesta aplicació. Les propietats específiques que s’han canviat són:

  • layout_width i layout_height: s’han especificat mides exactes per tal que les imatges tinguin totes la mateixa mida, independentment de la mida original de les fotografies.
  • background: color de fons de cada imatge, codificat en hexadecimal amb el format #RRGGBB, on RR és el codi per al vermell (red), GG per al verd (green) i BB per al blau (blue). Cada imatge té un color de fons diferent, en aquest exemple.
  • padding: les imatges tindran un marc de 3 unitats d’amplada amb el color de fons que s’hagi especificat a cada imatge.
  • clickable: indica que es pot clicar a la imatge.
  • onClick: nom del mètode que es cridarà quan es cliqui la imatge. Noteu que totes les imatges fan referència al mateix mètode, que més endavant haurà d’esbrinar quina imatge ha tocat l’usuari per tal de reproduir el so adient.
  • contentDescription: text de descripció de la imatge que serà utilitzat de cara als lectors de pantalla. Lògicament, cal afegir el text corresponent al fitxer strings.xml.

A continuació es pot veure el layout.xml complet d’aquesta aplicació, amb sis imatges que corresponen a les sis fotografies que s’han afegit al projecte:

  1. <LinearLayout xmlns:android ="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical" >
  6.  
  7. <LinearLayout
  8. android:layout_width="match_parent"
  9. android:layout_height="wrap_content"
  10. android:gravity="center_horizontal" >
  11.  
  12. <ImageView
  13. android:id="@+id/imageView1"
  14. android:layout_width="100dp"
  15. android:layout_height="100dp"
  16. android:background="#C000C0"
  17. android:contentDescription="@string/descripcio"
  18. android:padding="3dp"
  19. android:clickable="true"
  20. android:onClick="onClickImatgeAnimal"
  21. android:src="@drawable/anec" />
  22.  
  23. <ImageView
  24. android:id="@+id/imageView2"
  25. android:layout_width="100dp"
  26. android:layout_height="100dp"
  27. android:src="@drawable/cat"
  28. android:background="#C0C000"
  29. android:padding="3dp"
  30. android:clickable="true"
  31. android:onClick="onClickImatgeAnimal"
  32. android:contentDescription="@string/descripcio" />
  33.  
  34. <ImageView
  35. android:id="@+id/imageView3"
  36. android:layout_width="100dp"
  37. android:layout_height="100dp"
  38. android:src="@drawable/cavall"
  39. android:background="#00C0C0"
  40. android:padding="3dp"
  41. android:clickable="true"
  42. android:onClick="onClickImatgeAnimal"
  43. android:contentDescription="@string/descripcio" />
  44.  
  45. </LinearLayout>
  46.  
  47. <LinearLayout
  48. android:layout_width="match_parent"
  49. android:layout_height="wrap_content"
  50. android:gravity="center_horizontal">
  51.  
  52. <ImageView
  53. android:id="@+id/imageView4"
  54. android:layout_width="100dp"
  55. android:layout_height="100dp"
  56. android:src="@drawable/gos"
  57. android:background="#00C000"
  58. android:padding="3dp"
  59. android:clickable="true"
  60. android:onClick="onClickImatgeAnimal"
  61. android:contentDescription="@string/descripcio" />
  62.  
  63. <ImageView
  64. android:id="@+id/imageView5"
  65. android:layout_width="100dp"
  66. android:layout_height="100dp"
  67. android:src="@drawable/porc"
  68. android:background="#0000C0"
  69. android:padding="3dp"
  70. android:clickable="true"
  71. android:onClick="onClickImatgeAnimal"
  72. android:contentDescription="@string/descripcio" />
  73.  
  74. <ImageView
  75. android:id="@+id/imageView6"
  76. android:layout_width="100dp"
  77. android:layout_height="100dp"
  78. android:src="@drawable/vaca"
  79. android:background="#C00000"
  80. android:padding="3dp"
  81. android:clickable="true"
  82. android:onClick="onClickImatgeAnimal"
  83. android:contentDescription="@string/descripcio" />
  84. </LinearLayout>
  85.  
  86. </LinearLayout>

Caldrà afegir els strings corresponents a /res/values/strings.xml:

  1. <resources>
  2.  
  3. <string name="app_name">PianoInfantil</string>
  4. <string name="hello_world">Hello world!</string>
  5. <string name="action_settings">Settings</string>
  6. <string name="title_activity_main">MainActivity</string>
  7. <string name="descripcio">Foto d\'un animal</string>
  8.  
  9. </resources>

A la figura es pot veure l’aspecte de l’aplicació un cop executada a l’emulador d’Android. Tot i que es pot executar, és molt important no clicar cap imatge perquè el mètode onClickImatgeAnimal encara no s’ha creat i això faria fallar l’aplicació.

Figura Aspecte de l’aplicació

Animació de les imatges

Per tal de donar una resposta visual a les operacions dels usuaris (que són nens petits), s’ha d’afegir una animació per interpolació que s’activi quan es clica una imatge. L’activació de l’animació s’ha de fer al mètode de resposta al clic a la imatge, en aquest cas el mètode onClickImatgeAnimal. Però en primer lloc s’ha de definir l’animació: feu clic amb el botó dret a la carpeta res/ , seleccioneu New/Android resource file, poseu de nom girar.xml i escolliu com a Resource type el valor Animation tal com es veu a la figura.

Figura Creació d’una animació

A aquest nou fitxer s’hi defineix una animació que, en aquest cas, el que farà és rotar la imatge 360° en un temps d’un segon (1000 mil·lisegons). El pivot es situa just al mig de la imatge per tal que rotin sobre elles mateixes. El contingut de girar.xml és el següent:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <set xmlns:android="http://schemas.android.com/apk/res/android">
  3. <rotate
  4. android:fromDegrees="0"
  5. android:toDegrees="360"
  6. android:pivotX="50%"
  7. android:pivotY="50%"
  8. android:duration="1000" />
  9. </set>

Això, però, no fa que les imatges girin quan l’usuari les clica; cal engegar l’animació cada cop que es produeix un clic. Al fitxer Java de l’activitat principal s’hi ha d’afegir el mètode onClickImatgeAnimal, que és el que s’executarà cada cop que l’usuari cliqui una imatge qualsevol (totes les imatges activen el mateix mètode). De moment, l’única responsabilitat del mètode és carregar i executar l’animació quan la imatge es clica. Noteu que els mètodes de tipus onClick reben com a paràmetre la vista (ImageView, en aquest cas) on s’ha clicat, amb la qual cosa el mètode ja sap directament a quina imatge cal aplicar l’animació. El codi que s’ha d’afegir al MainActivity és el següent:

  1. public void onClickImatgeAnimal(View v) {
  2. Animation animacio = AnimationUtils.loadAnimation(this, R.anim.girar);
  3. v.startAnimation(animacio);
  4. }

Reproducció dels sons

Tal com s’ha especificat, quan els petits usuaris premin una imatge l’aplicació ha de reproduir el so corresponent a l’animal respectiu. Com que no hi ha gaires sons i els que hi ha no ocupen massa espai (són curts i de baixa definició), la forma més senzilla d’afegir-los a l’aplicació és crear la carpeta /res/raw/ i arrossegar-los-hi (recordeu que per fer això necessiteu estar a la pestanya project del package explorer). Els formats suportats són mp3, ogg i wav. A la figura es pot veure el resultat d’aquesta operació, amb els sis fitxers ogg.

Figura Fitxers d’àudio afegits al projecte

Els sons es reprodueixen quan l’usuari prem una imatge, és a dir, que la reproducció s’ha d’iniciar al mètode onClickImatgeAnimal. Però com que aquest mètode és el mateix per a tots sis botons, cal que es distingeixi quin és el botó que s’ha clicat per tal de reproduir la pista corresponent.

Una forma senzilla de resoldre aquest problema és veure quin és l’identificador de la imatge que s’ha clicat i, en funció d’aquest valor, reproduir una pista d’àudio o una altra. El codi que fa aquesta operació s’ha d’afegir al final del mètode onClickImatgeAnimal:

El codi d'onClickImatgrAnimal quedarà de la següent manera:

  1. public void onClickImatgeAnimal(View v) {
  2. Animation animacio = AnimationUtils.loadAnimation(this, R.anim.girar);
  3. v.startAnimation(animacio);
  4. MediaPlayer so = null;
  5. switch (v.getId()) {
  6. case R.id.imageView1:
  7. so = MediaPlayer.create(this, R.raw.anec);
  8. break;
  9. case R.id.imageView2:
  10. so = MediaPlayer.create(this, R.raw.gat);
  11. break;
  12. case R.id.imageView3:
  13. so = MediaPlayer.create(this, R.raw.cavall);
  14. break;
  15. case R.id.imageView4:
  16. so = MediaPlayer.create(this, R.raw.gos);
  17. break;
  18. case R.id.imageView5:
  19. so = MediaPlayer.create(this, R.raw.porc);
  20. break;
  21. case R.id.imageView6:
  22. so = MediaPlayer.create(this, R.raw.vaca);
  23. break;
  24. }
  25.  
  26. so.start();
  27. }

Ara ja podeu executar l’aplicació i provar amb els diferents sons. Si cliqueu moltes vegades, potser arribarà un punt en què les imatges girin però els sons dels animals no s’escoltin més. La causa d’aquest problema ve del fet que cada cop que es clica una imatge es crea una nova instància de MediaPlayer, però quan acaba la reproducció no s’alliberen els recursos emprats pel MediaPlayer i per aquest motiu arriba un punt que no es poden crear noves instàncies de MediaPlayer.

En previsió d’aquest problema, MediaPlayer permet afegir-li un objecte que s’activarà en completar la reproducció de la pista d’àudio i que l’únic que ha de fer és alliberar el MediaPlayer quan acaba. El codi següent, que és l’encarregat de fer-ho, s’ha d’afegir al final del mètode onClickImatgeAnimal:

  1. // Alliberar el MediaPlayer quan acabi de reproduir la pista d'àudio
  2. so.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
  3.  
  4. @Override
  5. public void onCompletion(MediaPlayer mp) {
  6. mp.release();
  7. }
  8. });

Amb això ja teniu una aplicació d’entreteniment infantil aprovada per uns quants nens que s’han passat una estona jugant-hi.

Anar a la pàgina anterior:
Programació multimèdia
Anar a la pàgina següent:
Exercicis d'autoavaluació