lawer / apunts_m08

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Apunts M08

L’objectiu d’aquestos apunts es guiar-vos en la creació d’una serie d’aplicacions de dificultat creixent.

Si seguiu el passos i completeu els exercicis adquirireu els conceptes i tècniques necessaris per a poder realitzar les vostres propies aplicacions per al SO Android.

Crear una aplicació que ens permeta portar el compte de vides i verins que tinga cada jugador en una partida de Magic.

S’han de mantindre els contadors si es gira la pantalla.

S’ha de poder resetejar els contadors en una opció de Menú.

  • Creem un nou projecte

    nou projecte

    No es necessari el suport per a C++.

  • Triem el API level

    Triem el API level

    El API level determina les llibreries que tindrem disponibles i es correspon a les diferents versions d’Android.

    Quan major siga aquest valor menys dependrem de la llibreria de compatibilitat i tindrem accés a eines més actualitzades; al mateix temps, però, la nostra aplicació es podrà executar en un nombre més reduït de mòbils.

    Nosaltres utilitzarem el nivell 16.

  • Creem una nova activitat de tipus Basic Activity

    Nova Activitat

  • Deixem el nom MainActivity. Seleccionem l’opció Use a Fragment.

    fragment

    Sempre utilitzarem fragments en les nostres apps, ja que ens facilitzarà una posterior adaptació a tabletes.

  • Esperem mentre es crea el nou projecte

Hem de dissenyar un layout el més paregut possible a la següent imatge: interficie final

Els passos son el següents:

  • En acabar de crear-se el projecte sens presentarà la interfície de disseny

    design

  • Hem de verificar que es tracta d’un ConstraintLayout

  • Agregarem una guia horitzontal que ens servirà per a separar les dues zones de l’aplicació

    guia horitzontal
    • Farem click en la part esquerra del document fins que l’icona passe a ser un %.

      esquerra - percent

    • Arrastrem la guia fins a deixar-la al 50%

  • Utilitzant l’eina New Vector Asset creem imatges per al nostres botons.

    vector asset

    • Necessitarem icones per passar vides d’un jugador a un altre (fletxa amunt i fletxa avall) i per a guanyar i perdre vides (cor ple i cor buit).

  • Situem els ImageButtons (botons amb imatge) de les fletxes

    • Els utilitzarem per passar vides d’un jugador a un altre

    • Com volem que estiguen en la part central de la pantalla utilitzarem la guia central com a referència en l’eix vertical

    • Per a que ocupen tota la pantalla fixarem els constraints esquerre i dret als laterals i fixarem com la opció Layout Width el valor match_parent (ocupar tot el valor del pare).

    • Per últim, llevarem el marge entre els botons

    • Utilitzant la propietat tint pintarem les icones de vermell.

    • El resultat final ha de ser semblant al següent:

      fletxes

  • Situem els Buttons (botons de text) per als verins

    • Quedaran anclats als cantons (dalt-esquerra, dalt-dreta, baix-dreta, baix-esquerra - en el sentit de les agulles del rellotge).

    • Deixarem el tamany dels botons per defecte

    • Han de tindre color verd.

    • El resultat ha de ser semblant al següent:

      verins

  • Situem els ImageButtons per a les vides.

    • Els utilitzarem per a sumar i restar vides de cada un dels jugadors.

    • Els pintarem de color vermell.

    • Constraints:

      • Cada botó anirà fixat al botó de verí més proper i a la guia central en el sentit vertical

      • En sentit horitzontal agafaran les referencies del botó de verí més proper.

    • Els botons tindran el mateix tamany horitzontal que els botons de verí (opció wrap_content per a Layout Width).

    • Per últim, llevarem el marge entre els botons

    • Utilitzant la propietat tint pintarem les icones de vermell.

    • Resultat:

      botons vida

  • TextViews pels contadors

    • Estaran centrats en la meitat superior i inferior del layout, respectivament

    • Tamany (TextSize): 30sp

    • Resultat:

      textviews

  • Fixar IDs

    • Per a poder referenciar els botons i TextViews des de el codi hem de donar un ID a cadascun d’ells.

El primer pas abans de poder assignar lògica als botons de la nostra interfície és el d’utilitzar findViewById per referenciar-los.

El procés serà el següent:

  • Passem a la pantalla de codi principal.(app/java/MainActivityFragment.java).

  • Accedim al objecte que fa referència al fragment (view) ja que aquest conté el métode findViewById. Guardarem una referència a aquest objecte

    • Substituirem el codi

      return inflater.inflate(R.layout.fragment_main, container, false)

      per

      View view = inflater.inflate(R.layout.fragment_main, container, false);
      
      //Aquí van les crides a findViewById
      
      return view;

      Aquest codi es troba en el mètode onCreateView, el que s’executa al inicialitzar el fragment.

  • Fem totes les crides a findViewById

    • Necessitarem accedit a tots el botons, botons amb imatge i textos (Button, ImageButton i TextView);

    • La sintaxi básica és

      TipusComponent nom = view.findViewById(R.id.idComponent) (1)
      1. R es un classe especial autogenerada per l’Android SDK. R.id conté tots els ids declarats en els Layouts.

    • Resultat:

      View view = inflater.inflate(R.layout.fragment_main, container, false);
      
      ImageButton lifetwotoone = view.findViewById(R.id.lifetwotoone);
      ImageButton lifeonetotwo = view.findViewById(R.id.lifeonetotwo);
      Button p1poisonmore = view.findViewById(R.id.p1poisonmore);
      Button p1poisonless = view.findViewById(R.id.p1poisonless);
      Button p2poisonmore = view.findViewById(R.id.p2poisonmore);
      Button p2poisonless = view.findViewById(R.id.p2poisonless);
      ImageButton p1lifemore = view.findViewById(R.id.p1lifemore);
      ImageButton p2lifemore = view.findViewById(R.id.p2lifemore);
      ImageButton p2lifeless = view.findViewById(R.id.p2lifeless);
      ImageButton p1lifeless = view.findViewById(R.id.p1lifeless);
      TextView counter1 = view.findViewById(R.id.counterp1);
      TextView counter2 = view.findViewById(R.id.counterp2);
      
      return view;

El següent pas serà el de definir com volem que s’emmagatzemen les dades en la nostra aplicació.

Al ser un exemple tan senzill tindrem prou en quatre variables privades situades en el mateix fragment.

public class MainActivityFragment extends Fragment { //(1)

private int life1 = 20; //(2)
private int life2 = 20; //(3)
private int poison1 = 0; //(4)
private int poison2 = 0; //(5)

public MainActivityFragment() { //(6)
  1. Definició de la classe

  2. Vida del jugador 1

  3. Vida del jugador 2

  4. Verins del jugador 1

  5. Verins del jugador 2

  6. Constructor de la classe

També haurem de definir les operacions que es podran realitzar sobre les dades.

Tindrem vuit accions possibles, les referides a incrementar i decrementar les vides i verins de cada jugador..

public void incLife1(){
    life1++;
}

public void incLife2(){
    life2++;
}

public void decLife1(){
    life1--;
}

public void decLife2(){
    life2--;
}

public void incPoison1(){
    poison1++;
}

public void incPoison2(){
    poison2++;
}

public void decPoison1(){
    poison1--;
}

public void decPoison2(){
    poison2--;
}

Per a poder modificar les dades quan es pressionen els botons hem d’utilitzar els gestor d’events (Events Handlers) que s’han d’agregar als cotrol que hem obtingut utilitzant findViewById.

La sintaxi general seria:

control.setEvent((View view)) -> { (1) (2)
    // Aquí aniria el nostre codi.
}
  1. Utilitzem una funcionalitat de Java anomenada funcions lambda.

    Ens permeten substituir una classe amb sols un mètode; reduïnt molt el codi que hem d’escriure.

    Més informació: Oracle, ECODEUP

  2. view en aquest cas, es referirà al control causant de l’event.

Anirem assignant els diferents events a les crides del nostre model de dades; d’aquesta manera conforme anem fent click s’anirà modificant el valor de les variables.

Tindrem un resultat semblant al següent:

lifeonetotwo.setOnClickListener((View view) -> {
    decLife1();
    incLife2();
});

lifetwotoone.setOnClickListener((View view) -> {
    decLife2();
    incLife1();
});

p1poisonmore.setOnClickListener((View view) -> {
    incPoison1();
});

p1poisonless.setOnClickListener((View view) -> {
    decPoison1();
});

p2poisonmore.setOnClickListener((View view) -> {
    incPoison2();
});

p2poisonless.setOnClickListener((View view) -> {
    decPoison2();
});

p1lifemore.setOnClickListener((View view) -> {
    incLife1();
});

p2lifemore.setOnClickListener((View view) -> {
    incLife2();
});

p1lifeless.setOnClickListener((View view) -> {
    devLife1();
});

p2lifeless.setOnClickListener((View view) -> {
    devLife2();
});

Com el codi es molt simple podem estalviar la creació de tantes funcions lambda agrupant-les en una sola que tinga un switch.

View.OnClickListener listener = (View view) -> {
    switch (view.getId()) { // (1)
        case R.id.lifeonetotwo:
            decLife1();
            incLife2();
            break;

        case R.id.lifetwotoone:
            decLife2();
            incLife1();
            break;

        case R.id.p1lifeless:
            decLife1();
            break;

        case R.id.p1lifemore:
            incLife1();
            break;

        case R.id.p1poisonless:
            decPoison1();
            break;

        case R.id.p1poisonmore:
            incPoison1();
            break;

        case R.id.p2lifeless:
            decLife2();
            break;

        case R.id.p2lifemore:
            incLife2();
            break;

        case R.id.p2poisonless:
            decPoison2();
            break;

        case R.id.p2poisonmore:
            incPoison2();
            break;
    }
};

lifetwotoone.setOnClickListener(listener);
lifeonetotwo.setOnClickListener(listener);
p1poisonmore.setOnClickListener(listener);
p1poisonless.setOnClickListener(listener);
p2poisonmore.setOnClickListener(listener);
p2poisonless.setOnClickListener(listener);
p1lifemore.setOnClickListener(listener);
p2lifemore.setOnClickListener(listener);
p1lifeless.setOnClickListener(listener);
p2lifeless.setOnClickListener(listener);
  1. Obtenim l’identificador del botó polsat.

Per a mostrar les dades haurem de modificar la variable text utilitzant el method setText del TextView.

Crearem un métode que actualitze els textViews, per a millorar la reusabilitat.

private void updateViews() {
    counter1.setText(String.format("%d/%d", life1, poison1));
    counter2.setText(String.format("%d/%d", life2, poison2));
}

Per últim, farem una crida al métode al final del onClickListener.

//...
p2lifeless.setOnClickListener(listener);

updateViews();

D’aquesta forma, cada volta que polsem un botó s’actualizaran els contadors.

Si, en la aplicació oberta, girem el telèfon podem veure com les dades es perden.

Android, per fer que la pantalla s’adapte a les noves dimensions, ha recreat l’Activity i tornat a executar el métode onCreateView tornat a inicialitzar les nostres dades al valor inicial.

Si no volem que passe aquest fenomen hem d’aprofitar les funcionalitats que ens dona Android per aquesta tasca.

EL primer pas serà guardar el valor de les nostres dades just abans de que s’esborrin.

Android ens proporciona per aquesta tasca el métode onSaveInstanceState, que si l’implementem ens permet posar les dades en un objecte semblant a un HashMap anomentat Bundle que Android guardarà.

El métode quedarà així:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    outState.putInt("life1", life1); (1)
    outState.putInt("life2", life2);
    outState.putInt("poison1", poison1);
    outState.putInt("poison2", poison2);
}
  1. Guardem les dades en el Bundle.

Una volta s’han reconstruït l’activitat i el fragment s’han de recuperar les dades anteriors.

Si treballem amb fragments, com és el nostre cas, la forma de fer-ho és en el métode onCreateView que té com a paràmetre un objecte de tipus Bundle anomenat savedInstanceState.

D’aquesta forma, agafarem aquest objecte, extreurem les dades de l’objecte, inicialitzarem les dades en les que provenen del Bundle i, per últim, tornarem a actualitzar els contadors.

Exemple:

TextView counter2 = view.findViewById(R.id.textView4);

(1)

if (savedInstanceState != null) {
    life1 = savedInstanceState.getInt("life1"); (2)
    life2 = savedInstanceState.getInt("life2");
    poison1 = savedInstanceState.getInt("poison1");
    poison2 = savedInstanceState.getInt("poison2");

    updateViews(); (3)
}

View.OnClickListener listener = (View view) -> {
  1. Insertem el codi després de fer els findViewById i abans de crear els listeners.

  2. Extraiem les dades

  3. Actualitzem els contadors

About


Languages

Language:CSS 100.0%