L'un des aspects les plus intéressants des spécifications de Material Design est la continuité visuelle entre les activités. Avec seulement quelques lignes de code, les nouvelles API Lollipop vous permettent de faire une transition significative entre deux activités, grâce à des animations transparentes et continues. Cela brise les limites classiques de l'activité des versions précédentes d'Android et permet à l'utilisateur de comprendre comment les éléments vont d'un point à un autre..
Dans ce didacticiel, je vais vous montrer comment atteindre ce résultat, en rendant un exemple d'application conforme aux consignes de Google relatives à la conception de matériaux..
Dans ce tutoriel, je suppose que vous êtes déjà familiarisé avec le développement Android et que vous utilisez Android Studio comme IDE. J'utiliserai intensivement les intentions d'Android, en supposant une connaissance de base du cycle de vie de l'activité et du nouveau RecyclerVoir
widget introduit avec API 21, Juin dernier. Je ne vais pas me plonger dans les détails de ce cours, mais si cela vous intéresse, vous pouvez trouver une bonne explication dans ce tutoriel Tuts +..
La structure de base de l'application est simple. Il y a deux activités, une principale, MainActivity.java, dont la tâche est d’afficher une liste d’articles et une seconde, DetailActivity.java, qui affichera les détails de l'élément sélectionné dans la liste précédente.
RecyclerVoir
WidgetPour afficher la liste des éléments, l’activité principale utilisera le RecyclerVoir
widget introduit dans Android Lollipop. La première chose à faire est d’ajouter la ligne suivante au les dépendances section dans votre projet build.grade fichier pour activer la compatibilité ascendante:
compiler 'com.android.support:recyclerview-v7:+'
Par souci de brièveté, nous ne définirons pas une base de données réelle ni une source de données similaire pour l'application. Au lieu de cela, nous allons utiliser une classe personnalisée, Contact
. Chaque élément est associé à un nom, une couleur et des informations de contact de base. C’est ce que la mise en œuvre de la Contact
la classe ressemble à:
public class Contact // Les champs associés à la personne privée final String mName, mPhone, mEmail, mCity, mColor; Contact (Nom de chaîne, Couleur de chaîne, Téléphone de chaîne, Email de chaîne, Ville de chaîne) mName = name; mCouleur = couleur; mPhone = téléphone; mEmail = email; mCity = ville; // Cette méthode permet d'obtenir l'élément associé à un identifiant particulier, // généré de manière unique par la méthode getId définie ci-dessous. Public statique Contact getItem (int id) pour (élément de contact: CONTACTS) if (item.getId () == id) return item; return null; // puisque mName et mPhone combinés sont sûrement uniques, // nous n'avons pas besoin d'ajouter un autre champ id public int getId () return mName.hashCode () + mPhone.hashCode (); énumération statique publique Field NAME, COLOR, PHONE, EMAIL, CITY public String get (Champ f) switch (f) case COLOR: return mColor; TÉLÉPHONE: retour mPhone; EMAIL du cas: renvoyer mEmail; case CITY: retour mCity; case NAME: défaut: return mName;
Vous vous retrouverez avec un joli conteneur pour les informations qui vous intéressent. Mais nous devons le remplir avec certaines données. Au sommet de la Contact
classe, ajoutez le code suivant pour renseigner le jeu de données.
En définissant les données comme Publique
et statique
, chaque classe du projet est capable de le lire. En un sens, nous imitons le comportement d’une base de données avec l’exception que nous la codons en dur dans une classe..
public statique final Contact [] CONTACTS = nouveau contact [] nouveau contact ("John", "# 33b5e5", "+01 123456789", "[email protected]", "Venise"), nouveau contact ("Valter" , "# ffbb33", "+01 987654321", "[email protected]", "Bologne"), nouveau contact ("Eadwine", "# ff4444", "+01 123456789", "[email protected]" , "Vérone"), nouveau contact ("Teddy", "# 99cc00", "+01 987654321", "[email protected]", "Rome"), nouveau contact ("Ives", "# 33b5e5", " +01 11235813 "," [email protected] "," Milan "), nouveau contact (" Alajos "," # ffbb33 "," +01 123456789 "," [email protected] "," Bologne "), nouveau Contact ("Gianluca", "# ff4444", "+01 11235813", "[email protected]", "Padova"), nouveau contact ("Fane", "# 99cc00", "+01 987654321", "fane @ exemple.com "," Venise "),;
La présentation de l'activité principale est simple, car la liste remplira tout l'écran. La mise en page comprend un Disposition relative
comme la racine, mais il peut tout aussi bien être un LinearLayout
aussi et RecyclerVoir
comme son seul enfant.
Parce que le RecyclerVoir
widget organise les sous-éléments et rien de plus, vous devez également concevoir la mise en page d'un élément de liste unique. Nous voulons avoir un cercle de couleur à gauche de chaque élément de la liste de contacts. Vous devez donc définir le dessin. cercle.xml.
Vous avez maintenant tous les éléments nécessaires pour définir la mise en page de l'élément de liste.
RecyclerVoir
Nous sommes presque arrivés à la fin de la première partie du didacticiel. Tu dois encore écrire le RecyclerView.ViewHolder
et le RecyclerView.Adapter
, et tout affecter à la vue associée dans le onCreate
méthode de l'activité principale. Dans ce cas, le RecyclerView.ViewHolder
doit également être capable de gérer les clics, il vous faudra donc ajouter une classe spécifique capable de le faire. Commençons à définir la classe responsable de la gestion des clics.
Classe publique RecyclerClickListener implémente RecyclerView.OnItemTouchListener private OnItemClickListener mListener; GestureDetector mGestureDetector; interface publique OnItemClickListener public void onItemClick (Vue de la vue, position int); public RecyclerClickListener (contexte de contexte, écouteur OnItemClickListener) mListener = listener; mGestureDetector = new GestureDetector (contexte, new GestureDetector.SimpleOnGestureListener () @Override public boolean onSingleTapUp (MotionEvent e) return true;); @Override public boolean onInterceptTouchEvent (vue RecyclerView, MotionEvent e) View childView = view.findChildViewUnder (e.getX (), e.getY ()); if (childView! = null && mListener! = null && mGestureDetector.onTouchEvent (e)) mListener.onItemClick (childView, view.getChildPosition (childView)); retourne vrai; return false; @Override public void onTouchEvent (vue RecyclerView, MotionEvent motionEvent)
Il est nécessaire de spécifier le RecyclerView.Adapter
, que je vais appeler ça Gestionnaire de données
. Il est responsable du chargement des données et de leur insertion dans les vues de la liste. Cette classe de gestionnaire de données contiendra également la définition du RecyclerView.ViewHolder
.
Classe publique DataManager étend RecyclerView.Adapterpublic static class RecyclerViewHolder étend RecyclerView.ViewHolder TextView mName, mPhone; Voir mCircle; RecyclerViewHolder (Voir itemView) super (itemView); mName = (TextView) itemView.findViewById (R.id.CONTACT_name); mPhone = (TextView) itemView.findViewById (R.id.CONTACT_phone); mCircle = itemView.findViewById (R.id.CONTACT_circle); @Override public RecyclerViewHolder onCreateViewHolder (ViewGroup viewGroup, int i) View v = LayoutInflater.from (viewGroup.getContext ()) .flate (R.layout.contact_item, viewGroup, false); renvoyer le nouveau RecyclerViewHolder (v); @Override public void onBindViewHolder (RecyclerViewHolder viewHolder, int i) // extrait l'élément unique du tableau principal final Contact contact = Contact.CONTACTS [i]; // Définit les valeurs viewHolder.mName.setText (contact.get (Contact.Field.NAME)); viewHolder.mPhone.setText (contact.get (Contact.Field.PHONE)); // Définit la couleur de la forme GradientDrawable bgShape = (GradientDrawable) viewHolder.mCircle.getBackground (); bgShape.setColor (Color.parseColor (contact.get (Contact.Field.COLOR))); @Override public int getItemCount () return Contact.CONTACTS.length;
Enfin, ajoutez le code suivant à la onCreate
méthode, ci-dessous setContentView.
L'activité principale est prête.
RecyclerView rv = (RecyclerView) findViewById (R.id.rv); // référence de présentation LinearLayoutManager llm = new LinearLayoutManager (this); rv.setLayoutManager (llm); rv.setHasFixedSize (true); // pour améliorer les performances rv.setAdapter (new DataManager ()); // le gestionnaire de données est assignateur au rv RV.addOnItemTouchListener (// et le clic est géré nouvel RecyclerClickListener (this, nouveau RecyclerClickListener.OnItemClickListener () @Override public null surItemClick (View view, position int.) // STUB: // Le clic sur l'élément doit être traité));
Voici à quoi ressemble l'application si vous la construisez et l'exécutez..
La deuxième activité est beaucoup plus simple. Il prend l'ID du contact sélectionné et récupère les informations supplémentaires que la première activité ne montre pas.
Du point de vue de la conception, la présentation de cette activité est essentielle car il s’agit de la partie la plus importante de l’application. Mais pour ce qui concerne le XML, c'est trivial. La mise en page est une série de Affichage
instances positionnées de manière agréable, en utilisant Disposition relative
et LinearLayout
. Voici à quoi ressemble la mise en page:
Puisque les deux activités sont liées par une intention, vous devez envoyer des informations permettant à la deuxième activité de comprendre lesquelles.contacter vous demandé les détails.
Une option peut être d'utiliser la variable de position comme référence. La position de l'élément dans la liste correspond à la position de l'élément dans le tableau, il n'y a donc rien de mal à utiliser cet entier comme référence unique..
Cela fonctionnerait, mais si vous utilisez cette approche et, pour une raison quelconque, le jeu de données est modifié à l'exécution, la référence ne correspondra pas au contact qui vous intéresse. C'est pourquoi il est préférable d'utiliser un ID.ad hoc. Cette information est la getId
méthode définie dans le Contact
classe.
Modifier le onItemClick
gestionnaire de la liste des éléments comme indiqué ci-dessous.
@Override public void onItemClick (Vue d'affichage, position int) Intention d'intention = nouvelle intention (MainActivity.this, DetailsActivity.class); intent.putExtra (DetailsActivity.ID, Contact.CONTACTS [position] .getId ()); startActivity (intention);
le DétailsActivité
recevra les informations du Intention
extras et construire le bon objet en utilisant l’ID comme référence. Ceci est montré dans le bloc de code suivant.
// Avant la version finale publique statique onCreate String ID = "ID"; public Contact mContact;
// Dans onCreate, après la méthode setContentView mContact = Contact.getItem (getIntent (). GetIntExtra (ID, 0));
Juste comme avant dans le onCreateViewHolder
méthode du RecylerView
, les vues sont initialisées à l'aide du findViewById
méthode et peuplé en utilisant Définir le texte
. Par exemple, pour configurer le champ de nom, procédez comme suit:
mName = (TextView) findViewById (R.id.DETAILS_name); mName.setText (mContact.get (Contact.Field.NAME));
Le processus est le même pour les autres champs. La deuxième activité est enfin prête.
Nous sommes enfin arrivés au cœur du didacticiel, en animant les deux activités à l'aide de la nouvelle méthode Lollipop pour la transition à l'aide d'un élément partagé..
La première chose à faire est de modifier votre thème dans le style.xml déposer dans le valeurs-v21 dossier. De cette manière, vous activez les transitions de contenu et définissez l'entrée et la sortie des vues qui ne sont pas partagées entre les deux activités..
Veuillez noter que votre projet doit cibler (et donc être compilé avec) au moins Android API 21.
Les animations seront ignoréessur les systèmes sur lesquels Lollipop n'est pas installé. Malheureusement, pour des raisons de performance, le AppCompat la bibliothèque ne fournit pas une compatibilité ascendante complète pour ces animations.
Une fois que vous avez édité votre style.xml fichier, vous devez signaler la relationentre les deux éléments communs des vues.
Dans notre exemple, les vues partagées sont le champ contenant le nom du contact, celui du numéro de téléphone et le cercle de couleur. Pour chacun d’eux, vous devez spécifier un nom de transition commun. Pour cette raison, commencez à ajouter dans le strings.xml resource file les éléments suivants:
transition: NOM transition: CERCLE transition: téléphone
Ensuite, pour chacune des trois paires, dans les fichiers de mise en page, ajoutez le android: transitionName
attribut avec la valeur correspondante. Pour le cercle de couleur, le code ressemble à ceci:
Grâce à cet attribut, Android saura quelles vues sont partagées entre les deux activités et animera correctement la transition. Répétez le même processus pour les deux autres vues.
Du point de vue du codage, vous devrez joindre un code spécifique ActivitéOptions
bundle à l'intention. La méthode dont vous avez besoin est makeSceneTransitionAnimation
, qui prend comme paramètres le contexte de l’application et autant d’éléments partagés que nous avons besoin. dans le onItemClick
méthode du RecyclerVoir
, éditer le précédemment défini Intention
comme ça:
@Override public void onItemClick (Vue d'affichage, position int) Intention d'intention = nouvelle intention (MainActivity.this, DetailsActivity.class); intent.putExtra (DetailsActivity.ID, Contact.CONTACTS [position] .getId ()); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation (// le contexte de l'activité MainActivity.this, //, pour chaque élément partagé, ajoutez à cette méthode un nouvel élément Pair, // contenant la référence de la vue que nous sommes en train de passer * à partir de *, // et la valeur de l'attribut transitionName new Pair(view.findViewById (R.id.CONTACT_circle), getString (R.string.transition_name_circle)), nouvelle paire (view.findViewById (R.id.CONTACT_name), getString (R.string.transition_name_name)), nouvelle paire (view.findViewById (R.id.CONTACT_phone), getString (R.string.transition_name_phone))); ActivityCompat.startActivity (MainActivity.this, intent, options.toBundle ());
Pour chaque élément partagé à animer, vous devrez ajouter à la makeSceneTransitionAnimation
méthode un nouveau Paire
article. Chaque Paire
a deux valeurs, la première est une référence à la vue en cours de transition de, le second est le valeur du nom de transition
attribut.
Faites attention lorsque vous importez le Paire
classe. Vous devrez inclure le android.support.v4.util
paquet, ne pas la android.util
paquet. En outre, n'oubliez pas d'utiliser ActivityCompat.startActivity
méthode au lieu de startActivity
méthode, sinon vous ne pourrez pas exécuter votre application sur des environnements avec une API inférieure à 16.
C'est tout. Vous avez terminé. C'est aussi simple que ça.
Dans ce didacticiel, vous avez appris à faire la transition entre deux activités partageant un ou plusieurs éléments communs, de manière transparente et transparente, pour une continuité visuellement agréable et significative..
Vous avez commencé par créer la première des deux activités, dont le rôle est d’afficher la liste des contacts. Vous avez ensuite terminé la deuxième activité en concevant sa mise en page et en mettant en œuvre un moyen de passer une référence unique entre les deux activités. Enfin, vous avez examiné la manière dont makeSceneTransitionAnimation
fonctionne, grâce au XML nom de transition
attribut.
Pour créer une véritable application ressemblant à Material Design, comme illustré dans les captures d'écran précédentes, vous devez également modifier les couleurs de votre thème. Modifiez votre thème de base dans le valeurs-v21 dossier pour obtenir un bon résultat.