androidbravo.univ-tln.fr/er/android/4-cours android 2017... · 2018-02-14 · android-iut geii...

34
ANDROID- IUT GEII 1 Juan BRAVO ANDROID INTERFACES GRAPHIQUES COMPLEXES

Upload: others

Post on 22-May-2020

24 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII

1

Juan BRAVO

ANDROID

INTERFACES GRAPHIQUES COMPLEXES

Page 2: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 2ANDROID-IUT GEII

Liste d'éléments

La classe RecyclerView Remplace l'ancienne classe ListView

Affichage d'éléments visuels sous forme de liste

Possibilité de personnaliser chaque élément

Notion d'adaptateur

Les adaptateurs Lien entre la source de données et l'affichage à réaliser

Objectif

Découplage entre les données et la vue

Permet de changer la mise en forme sans toucher aux classes 'métiers'RecyclerView Adapter

OnBindViewHolder link information between data source and view holder fields

onBindViewHolder(ViewHolder,3)

Page 3: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 3ANDROID-IUT GEII

RecyclerView

RecyclerView.Adapter Classe abstraite

Corps de certaines méthodes laissés volontairement vide

Non instantiable donc

A charge de l'utilisateur d'hériter et d'écrire de contenu des méthodes

Principales méthodes héritées

public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

– Objectif : création d'une vue (View) en fonction de vos besoins

public void onBindViewHolder(ViewHolder holder, int position)

– Objectif : fait le lien entre la vue précédemment crée et vos données (data binding)

Page 4: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 4ANDROID-IUT GEII

RecyclerView

Les étapes Création du type d'objet 'à afficher'

Type prédéfinis : String, Int , etc...

Type Utilisateur : création de classes

public class Student { private String nom; private String prenom; private Avatar avatar;

public String getNom() { return nom; }

public String getPrenom() { return prenom; }

public Avatar getAvatar() { return avatar; }

public Student(String nom, String prenom, Avatar avatar) { this.nom = nom; this.prenom = prenom; this.avatar = avatar; }}

public class Avatar { private Drawable avatarImage;

public Avatar(Drawable avatarImage) { this.avatarImage = avatarImage; }

public Drawable getAvatarImage() { return avatarImage; }}

Page 5: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 5ANDROID-IUT GEII

RecyclerView

Stockage des éléments en Java

Notion de conteneur et de collection

/////////////////////////////////////////ArrayList<int> al2 = new ArrayList<int>();al2.add(3);al2.add(2); al2.add(1);// exemple 1 de parcours de collectionIterator<int> iter2 = al2.iterator();while(iter2.hasNext()){ System.out.println(iter2.next());}al2.remove(2);// exemple 2 de parcours de collection for (int unEntier:al2){System.out.println(unEntier);}

Les collections sont génériques. Elles doivent pouvoir fonctionner pour différents typesSyntaxe côté utilisateur: ArrayList<MonTypeAMoi>

Exemple ArrayList

Page 6: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 6ANDROID-IUT GEII

RecyclerView

Exemple du dictionnaire

– Stockage sous forme clé+objet

HashMap<String, Color> dico = new HashMap<String, Color>();dico.put("rouge", new Color(200,0,0));dico.put("blanc", new Color(200,200,200));dico.put("marron", new Color(153,135,200));dico.put("violet", new Color(153,0,200));String colorKey = "marron";// recherche sur cléColor col= dico.get(colorKey);System.out.println("Clé: " + colorKey +" Moyenne: "+ col.ColorAverage());

dico.remove("marron");//itération avec modifIterator<Map.Entry<String, Color>> iterator = dico.entrySet().iterator();

while(iterator.hasNext()){ Map.Entry<String, Color> entry = iterator.next(); System.out.printf("clé : %s and Value: %s %n", entry.getKey(), entry.getValue().ColorAverage()); if (entry.getKey()=="blanc"){ iterator.remove(); } } //itération sans modif for(Map.Entry<String, Color> entry : dico.entrySet()){ System.out.printf("clé : %s and Value: %s %n", entry.getKey(), entry.getValue().ColorAverage()); }

Clé: marron Moyenne: 162clé : rouge and Value: 66 clé : violet and Value: 117 clé : blanc and Value: 200 clé : rouge and Value: 66 clé : violet and Value: 117

Page 7: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 7ANDROID-IUT GEII

RecyclerView

Adaptateur Création du layout

Repertoire ressouces>layout

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeightLarge" android:orientation="horizontal"

android:gravity="center">

<ImageViewandroid:id="@+id/img_avatar"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/designer_avatar" />

<TextView android:id="@+id/tv_fullName" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Oscar Amel"

android:textColor="@color/colorPrimary"/>

</LinearLayout>

Page 8: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 8ANDROID-IUT GEII

RecyclerView

Adaptateur « customisé »

Création d'une classe héritée de RecyclerView.Adapter

Un constructeur pour transmettre une référence vers les données

class StudentRecyclerViewAdapter extends RecyclerView.Adapter<StudentRecyclerViewAdapter.ViewHolder> { // private reference field pointing to our data private ArrayList<Student> refStudentList;

// ctor public StudentRecyclerViewAdapter(ArrayList<Student> studentList) { refStudentList=studentList; }

// model of the UI ViewHolder // this class is inner to our adapter public class ViewHolder extends RecyclerView.ViewHolder { public TextView fullName; public ImageView avatar;

public ViewHolder(View v) { super(v); fullName = (TextView) v.findViewById(R.id.tv_fullName) ; avatar = (ImageView) v.findViewById(R.id.img_avatar); } }

Page 9: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 9ANDROID-IUT GEII

Suite de la classe StudentRecyclerViewAdapter

// create ViewHolder // ViewHolder can be recycled for optimsition purpose @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.student_item, parent, false); ViewHolder vh = new ViewHolder(v); return vh; }

// link the UI ViewHolder model to our object model @Override public void onBindViewHolder(ViewHolder holder, int position) { Student currentItem = refStudentList.get(position); holder.fullName.setText(currentItem.getPrenom()+" "+currentItem.getNom()); Avatar itemcurrentAvatar=currentItem.getAvatar(); holder.avatar.setImageDrawable(itemcurrentAvatar.getAvatarImage()); }

// needed to explain when to rech the end @Override public int getItemCount() { return refStudentList.size(); }}// End of StudentRecyclerViewAdapter

Page 10: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 10ANDROID-IUT GEII

ListView

L'activité principale On place le RecyclerView

On lie le RecyclerView à l'adapteur

public class MainActivity extends AppCompatActivity { ArrayList<Student> studentList; private RecyclerView rvView;

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // STEP1: setup data (fill studentList) initStudentDataSource(); rvView = (RecyclerView) findViewById(R.id.rv_main); rvView.setHasFixedSize(true); // STEP2: CHOOSE layout LinearLayoutManager layoutManager = new LinearLayoutManager(this); rvView.setLayoutManager(layoutManager); // STEP3: instantiate StudentRecyclerViewAdapter StudentRecyclerViewAdapter adapter = new StudentRecyclerViewAdapter(studentList); // STEP4: link RecyclerView coming from activity_main to our custom adapter rvView.setAdapter(adapter); }

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" android:orientation="vertical">

<android.support.v7.widget.RecyclerView android:id="@+id/rv_main" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" />

</LinearLayout>

private void initStudentDataSource(){ studentList=new ArrayList(); Avatar refAvatar=new Avatar(ContextCompat.getDrawable(this, R.drawable.grimace)); Student refStudent= new Student("AMEL","Oscar",refAvatar); studentList.add(refStudent); refAvatar=new Avatar(ContextCompat.getDrawable(this, R.drawable.designer_avatar));Etc….

Page 11: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 11ANDROID-IUT GEII

ListView

Gestion du clic Plusieurs solutions possibles

Implémenter la setOnclickListener dans l'adapter (le +simple!! )

Implémenter recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() { ….

Implémenter le design pattern oberver entre le ViewHolder et l'activité parente

Utiliser des librairies pour la mise en place du RecyclerView

public ViewHolder(View v) { super(v); fullName = (TextView) v.findViewById(R.id.tv_fullName); avatar = (ImageView) v.findViewById(R.id.img_avatar);

v.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position=getAdapterPosition(); if (position != RecyclerView.NO_POSITION){ Snackbar.make(v, "Position "+position +" Clicked element " +refStudentList.get(position). getNom(), Snackbar.LENGTH_LONG).show(); } } });}

// Check if an item was //deleted, but the user //clicked it before the UI//removed it

https://guides.codepath.com/android/using-the-recyclerview

Page 12: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 12ANDROID-IUT GEII

Pour plus de fonctionnalités Librairies de la communauté open source

https://github.com/mikepenz/FastAdapter

https://github.com/davideas/FlexibleAdapter/wiki

Page 13: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 13ANDROID-IUT GEII

Fragments

Les fragments Permet de fragmenter la vue ( portion d'interfaces visuelles)

Objectifs :

Modularité de l'application

– Évolution application, Hétérogénéité des matériels cibles Réutilisation de portions codes

Scénario 1 Scénario 2

Page 14: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 14ANDROID-IUT GEII

Fragments

Cycle de vie d'un fragment Lié au cycle de vie de l'activité parente

Méthodes de callbacks des fragments appelées par l'activité parente

Cycle de vie d'une activité

Cycle de vie d'un fragment

Page 15: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 15ANDROID-IUT GEII

Fragments

Callbacks d'un fragmentonAttach Called when the Fragment is attached to its

parent Activity.Get a reference to the parent Activity.

onCreate Called to do the initial creation of the Fragment.

Initialize the Fragment.

onCreateView // Called once the Fragment has been created in order for it to // create its user interface.

// Create, or inflate the Fragment's UI, and return it. // If this Fragment has no UI then return null.

onActivityCreated // Called once the parent Activity and the Fragment's UI have // been created.

// Complete the Fragment initialization Ð particularly anything // that requires the parent Activity to be initialized or the // Fragment's view to be fully inflated.

onStart // Called at the start of the visible lifetime // Apply any required UI change now that the Fragment is visible.

onResume // Called at the start of the active lifetime. // Resume any paused UI updates, threads, or processes required // by the Fragment but suspended when it became inactive.

onPause // Called at the end of the active lifetime. // Suspend UI updates, threads, or CPU intensive processes // that don't need to be updated when the Activity isn't // the active foreground activity. // Persist all edits or state changes // as after this call the process is likely to be killed.

onSaveInstanceState // Called to save UI state changes at the // end of the active lifecycle.

// Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate, onCreateView, and // onCreateView if the parent Activity is killed and restarted.

onDestroyView // Called when the Fragment's View has been detached.

// Clean up resources related to the View.

onDestroy // Called at the end of the full lifetime. // Clean up any resources including ending threads, // closing database connections etc.

Page 16: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 16ANDROID-IUT GEII

Fragments

Exemplepublic class Fragment1 extends Fragment {

// Called when the Fragment is attached to its parent Activity.@Override

public void onAttach(Activity activity) {super.onAttach(activity);

// TODO: Get a reference to the parent Activity.Log.d("Fragment 1", "onAttach");

}

// Called to do the initial creation of the Fragment.@Override

public void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//// TODO: Initialize the Fragment.Log.d("Fragment 1", "onCreate");

}

// Called once the Fragment has been created in order for it to // create its user interface.

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO:Create, or inflate the Fragment's UI, and return it. // If this Fragment has no UI then return null. Log.d("Fragment 1", "onCreateView"); return inflater.inflate(R.layout.fragment1, container, false); }…........

Déclaration de 2 fragments mode paysage (balise fragment)

Définition aspect visuel d'un fragment

Code d'un fragment (intéraction etc..)

Page 17: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 17ANDROID-IUT GEII

Fragments

Fragments statiques Déclaration dans les ressources layout : balises fragment

<LinearLayout xmlns:....

<fragment android:name="com.example.staticfragment.Fragment1" android:id="@+id/list" android:layout_weight="0.25" android:layout_width="0dp" android:layout_height="match_parent" /></LinearLayout>

<LinearLayout xmlns:....... <fragment android:name="com.example.staticfragment.Fragment1" android:id="@+id/list" android:layout_weight="0.25" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.staticfragment.Fragment2" android:id="@+id/viewer" android:layout_weight="0.75" android:layout_width="0dp" android:layout_height="match_parent" />

rotation

Afin d’éviter plusieurs main.xml et de gérer correctement les différentes configurations cet exemple peut-être refactoriser à l’aide d’aliasing (voir poly styles)

Page 18: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 18ANDROID-IUT GEII

Fragments

Définition de l'interface d'un fragment

Comme d'habitude par le biais d'une ressource de type layout

Code du fragment

Surcharge des méthodes de callback

Gestion des interaction de l'IHM

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#00FF00" ><TextView android:id="@+id/txtFragment1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="This is fragment #1" /> </LinearLayout>

<fragment android:name="com.example.staticfragment.Fragment1" android:id="@+id/list" ….....</LinearLayout>

Page 19: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 19ANDROID-IUT GEII

Fragments

Exemple de code du fragment 1

public class MainActivity extends Activity {/** Called when the activity is first created. */

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }

Rappel : nous avons déclaré dans le layout de l'activité principale le (les) fragment(s)En fonction de l'orientation le bon layout est appelé (1 ou 2 fragments déclarés)

public class Fragment2 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View v=inflater.inflate(R.layout.fragment2, container, false); //---text view--- TextView txtFrg2 = (TextView) v.findViewById(R.id.txtFragment2); txtFrg2.setText("this is fragment 2"); txtFrg2.setTextColor(Color.BLUE); txtFrg2.setTypeface(Typeface.DEFAULT_BOLD); return (v); }

On récupère la vue désérialisée afin d'accéder au widget

TextView lbl = (TextView) getActivity().findViewById(R.id.lblFragment1);

Il est possible d'accéder à des widget d'autres fragments par le biais de getActivity()

Page 20: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 20ANDROID-IUT GEII

Fragments dynamiques Approche statique : les fragments sont figées à la compilation

Approche dynamique : possibilité de remplacer au run-time un fragment par un autre en fonction du contexte de l'application !

La structure des fichiers est la même mais la balise xml fragment n'est plus utilisée

Page 21: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 21ANDROID-IUT GEII

Etape 1 : les ressources Pas de balise Fragment

A la place : un conteneur de vue de type FrameLayout

Le fragment sera crée dynamiquement en Java puis placée à l'intérieur du Frame Layout

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=".........." android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <FrameLayout android:id="@+id/fragmentContainer1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" >

</FrameLayout>

<FrameLayout android:id="@+id/fragmentContainer2" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="2" android:visibility="gone"> </FrameLayout></LinearLayout>

Bonne pratique 2 FrameLayout en portrait ou landspace mais visibility gone en portrait

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android= ".........." android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#00FF00" ><TextView android:id="@+id/lblFragment1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="This is fragment #1" /> </LinearLayout>

Page 22: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 22ANDROID-IUT GEII

Etape 2 : création dynamique des fragments

public class MainActivity extends Activity {

@Overrideprotected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);setContentView(R.layout.main);

FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction =

fragmentManager.beginTransaction(); Fragment fragment1= (Fragment)fragmentManager.findFragmentById(R.id.fragmentContainer1); if (fragment1==null){ fragmentTransaction.add(R.id.fragmentContainer1, new Fragment1()); } Fragment fragment2= (Fragment)fragmentManager.findFragmentById(R.id.fragmentContainer2); if (fragment2==null){ fragmentTransaction.add(R.id.fragmentContainer2, new Fragment2()); } fragmentTransaction.commit();

}

La manipulation des fragments par le code passe par la classe FragmentManager

Création fragment et ajout dans le framelayout

Pourquoi if (fragment2==null) ?????

Lors d'une rotation l'activité et les fragments donc sont détruits puis RECREE automatiquement !!! L'astuce consiste à regarder si un fragment existe déjà dans le container.

Page 23: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 23ANDROID-IUT GEII

Erreur de conception courante

Analyse d'une rotation

Nous sommes en mode LANDNous passons en mode PORBOOOM

Le fragment Command Panel est détruit

Le fragment Command Panel est récrée automatiquement (indépendant de votre code)

Oui..Mais ou est le xml ????

Page 24: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 24ANDROID-IUT GEII

Mauvaise solution (mais fonctionnelle!)

Placer les ressources comme suit

Nous sommes en mode LANDNous passons en mode POR

Au moment de la recréation automatique des fragments (panel et détail) les layouts sont recherchés :1- layout-port : KO2- layout-xxx : KO3- layout-yyy: KO4- layout : OK ( layout = par défaut)

Il est préférable de regrouper tout les « sous-layouts » au même endroits

Page 25: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 25ANDROID-IUT GEII

Déclarer en mode portrait les containers pour TOUS les fragments

– Les containers non utilisés seront positionnés NON VISIBLE

En portrait 1 seul container de conservé

Page 26: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 26ANDROID-IUT GEII

Etape 3 : manipulation dynamique des fragments

@Overridepublic boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {case R.id.item1:FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); Fragment fragmentB= (Fragment)fragmentManager.findFragmentById(R.id.fragmentContainer2);

if (fragmentB instanceof Fragment2){ fragmentTransaction.replace(R.id.fragmentContainer2, new Fragment1() ); fragmentTransaction.replace(R.id.fragmentContainer1, new Fragment2()); } else{ fragmentTransaction.replace(R.id.fragmentContainer2, new Fragment2() ); fragmentTransaction.replace(R.id.fragmentContainer1, new Fragment1()); } fragmentTransaction.commit();Toast.makeText(this, "Fragment permut", Toast.LENGTH_SHORT).show(); return true;}return super.onOptionsItemSelected(item);}

Exploitation du polymorphismeUpcast

Page 27: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 27ANDROID-IUT GEII

Transmission de données Deux scénarios

FragmentA ->Activité Parente ou FragmentA->Activité Parente->FragmentB

Design pattern OBSERVATEUR

C'est le fragment qui émet un évenementPour ce faire, il maintient une liste d'abonnés à cet événement

C'est notre activité parent qui à l'écoute de l'événement (c'est l'abonnée)

Page 28: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 28ANDROID-IUT GEII

Pattern Observateur Application 1 : GPS

// Interface implémentée par tous les observateurs.public interface Observateur{ // Méthode appelée automatiquement lorsque l'état (position ou précision) du GPS change. public void actualiser(Observable o);}

// Affiche un résumé en console des informations (position) du GPS.public class AfficheResume implements Observateur{ public void actualiser(Observable o) { if(o instanceof Gps) { Gps g = (Gps) o; System.out.println("Position : "+g.getPosition()); }

http://design-patterns.fr/observateur-en-java

Page 29: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 29ANDROID-IUT GEII

// Classe représentant un GPS (appareil permettant de connaître sa position).public class Gps implements Observable{ private String position; private int precision; private ArrayList tabObservateur;// Tableau d'observateurs. // Constructeur. public Gps() { position="inconnue"; precision=0; tabObservateur=new ArrayList(); } // Permet d'ajouter (abonner) un observateur à l'écoute du GPS. public void ajouterObservateur(Observateur o) { tabObservateur.add(o); }

// Interface implémentée par toutes les classes souhaitant avoir des observateurs à leur écoute.public interface Observable{ // Méthode permettant d'ajouter (abonner) un observateur. public void ajouterObservateur(Observateur o); // Méthode permettant de supprimer (résilier) un observateur. public void supprimerObservateur(Observateur o); // Méthode qui permet d'avertir tous les observateurs lors d'un changement d'état. public void notifierObservateurs();}

Page 30: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 30ANDROID-IUT GEII

Pattern Observateur simplifiépublic class Fragment2 extends Fragment {private OnValidateEventListener eventValidateListener;

public interface OnValidateEventListener {public void onValidateEvent(EventRecord oneRecord);}@Override// Called when the Fragment is attached to its parent Activitypublic void onAttach(Activity activity) {super.onAttach(activity);// Get reference to parent Activity and check if parent implements listenertry {eventValidateListener = (OnValidateEventListener)activity;} catch (ClassCastException e) {throw new ClassCastException(activity.toString() +"must implement OnValidateEventListener");}}

@Overridepublic void onStart() {super.onStart();Button btn=(Button) getActivity().findViewById(R.id.btnFireEvent);btn.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {// Fire EventeventValidateListener.onValidateEvent(new EventRecord(SimpleEvent.ALERTE_TEMPERATURE));}});

Référence vers un abonné (ici l'activité parente ,qui devra donc implémenter

OnValidateEventListener)

Définition du contrat d'appel pour les observateurs

L'enregistrement se fait lorsque le fragment est attaché à son activité parente

( opération de UPCAST)

Le fragment signale l'événementAppel de la méthode onValidateEvent implanté par

l'observateur (Activité parente)

Je suis l'Observable (celui qui est observé)

Page 31: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 31ANDROID-IUT GEII

port com.example.listenerfragment.Fragment2.OnValidateEventListener;public class MainActivity extends Activityimplements OnValidateEventListener{

/** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }

// since MainActivity implements OnValidateEventListener // we need to implement onValidateEventpublic void onValidateEvent(EventRecord oneRecord) {// ACTION when event is firedTextView txt=(TextView)findViewById(R.id.txtMain);txt.setText(oneRecord.getEvent().name());

} }

Je dois respecter le contrat

J'implémente la méthode onValidateEventJ'exploite la donnée transmis par le Sujet

(observable)

Je suis l'Observateur (celui qui observe)

La communication d'un Fragment vers un autre doit passer par l'activité parente qui a pour charge d'appeler la méthode souhaitée

http://developer.android.com/training/basics/fragments/communicating.html

Page 32: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 32ANDROID-IUT GEII

Applications typiques des fragments Les menus tabulés

Google Map API v2

Fragment List et Fragment Détails

Mode portrait Mode paysage

<fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/map" android:layout_width="match_parent" android:layout_height="match_parent" android:name="com.google.android.gms.maps.MapFragment"/>

Page 33: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 33ANDROID-IUT GEII

ListFragment version express Les ressources

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:........ android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" >

<fragment android:id="@+id/listFragment" android:layout_width="match_parent" android:layout_height="match_parent" class="com.example.listfragmentsimple.ListFragment" /> </LinearLayout>

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:........ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >

<fragment android:id="@+id/detailFragment" android:layout_width="match_parent" android:layout_height="match_parent" class="com.example.listfragmentsimple.DetailFragment" />

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:...... android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" >

<fragment android:id="@+id/listFragment" android:layout_width="150dip" android:layout_height="match_parent" class="com.example.listfragmentsimple.ListFragment" ></fragment>

<fragment android:id="@+id/detailFragment" android:layout_width="match_parent" android:layout_height="match_parent" class="com.example.listfragmentsimple.DetailFragment" > </fragment>

</LinearLayout>

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="......... android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" >

<TextView android:id="@+id/detailsText" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="....... android:layout_marginTop="20dip" android:textSize="30dip" />

</LinearLayout>

LANDPORT

On remarquera l'absence de xml pour la mise en forme de la liste. Version express= layout fourni par défaut

Page 34: ANDROIDbravo.univ-tln.fr/er/Android/4-Cours Android 2017... · 2018-02-14 · ANDROID-IUT GEII ANDROID- IUT GEII 3 RecyclerView RecyclerView.Adapter Classe abstraite Corps de certaines

ANDROID- IUT GEII 34ANDROID-IUT GEII

Le code

Activité principale

Activité détails (mode PORT)

public class ListFragment extends android.app.ListFragment {private static final String VALUE = "value";private String[] values = {"Cupcake", "Donut", "Eclair", "Froyo", "Gingerbread", "Honeycomb", "Ice Cream Sandwich" };

@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);}

@Overridepublic void onActivityCreated(Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);

ArrayAdapter<String> adapter = new ArrayAdapter<String> (getActivity(),android.R.layout.simple_list_item_1, values);

setListAdapter(adapter);}

@Overridepublic void onListItemClick(ListView l, View v, int position, long id) {String item = (String) getListAdapter().getItem(position);

DetailFragment fragment = (DetailFragment) getFragmentManager().findFragmentById(R.id.detailFragment);

if (fragment != null && fragment.isInLayout()) {fragment.setText(item);}

Else {Intent intent = new Intent(getActivity().getApplicationContext(),DetailActivity.class);intent.putExtra(VALUE, item);startActivity(intent);}

Si fragment détail est présent et compris dans layout alors on est en mode LAND

Sinon on lance activité détails en passant par intent la donnée à afficher