38 votes

Conception du fragment : S'adapter à plusieurs dispositions d'écran en affichant/masquant des fragments au sein d'une même activité ?

J'essaie de comprendre comment utiliser les Fragments pour créer des applications qui s'adaptent bien à plusieurs écrans et mises en page. J'ai étudié quelques exemples :

  1. Les Fragments sur le guide du développeur Android.
  2. Application Google IO
  3. Échantillon de fragments de ActionBar Sherlock .

Tous ces éléments plaident en faveur d'une Activity l'approche :

  • Sur un grand écran, afficher un seul Activity avec plusieurs Fragment s
  • Sur un écran plus petit, divisez le Fragment entre plusieurs Activity s.

J'ai pensé à une autre approche - une seule Activity un :

  • Avoir un seul Activity avec tous les Fragment en son sein.
  • En fonction de la taille et de l'orientation de l'écran, affichez/masquez l'image appropriée. Fragment (s) (en utilisant FragmentTransaction.show() / FragmentTransaction.hide() ) .

Prenons le même exemple de "liste d'articles d'actualité/contenu d'articles" que celui utilisé dans le guide du développeur d'Android :

  • Avoir le News activité contenant à la fois un ArticleListFragment et ArticleReaderFragment .
  • Dans un onglet, les deux fragments sont toujours affichés.
  • Sur un téléphone, la touche ArticleReaderFragment est initialement caché. Lorsqu'un article est sélectionné dans la liste, l'icône ArticleListFragment est caché et le ArticleReaderFragment est affichée.

Quelqu'un a-t-il utilisé une approche similaire ? Y a-t-il des inconvénients pratiques à cette méthode ? Semble-t-elle meilleure/moins bonne par rapport à la méthode des activités multiples ? Par exemple, les fragments ne peuvent pas être affichés/cachés en XML - une seule activité est nécessaire. doit utiliser FragmentTransaction pour cela.


EDIT 1 : Description d'un scénario hypothétique

Imaginez une application capable d'afficher jusqu'à trois "volets" à la fois sur l'écran. En outre, voici les facteurs à prendre en considération :

  • Un téléphone ne peut afficher qu'un seul volet à la fois (indépendamment de l'orientation portrait/paysage).
  • Une tablette de 7 pouces peut afficher deux volets, divisés verticalement en mode portrait et horizontalement en mode paysage.
  • Une tablette de plus de 10 pouces peut afficher 2 volets, divisés verticalement en mode portrait ; 3 volets divisés horizontalement en mode paysage.

Pour des raisons de simplicité, ne parlons pas des écrans de télévision.

Maintenant, traduisons cela en termes de conception :

  • Nous avons trois fragments : Frag1, Frag2 et Frag3.
  • Dans le cas le plus simple, les trois fragments se trouvent dans une seule activité (appelée ActivitéA). Il s'agit du cas du paysage de 10 pouces.
  • L'autre cas "simple" est celui où chaque fragment se trouve dans sa propre activité - l'activité A contient le fragment 1 ; l'activité B contient le fragment 2 et l'activité C contient le fragment 3.

Jusqu'à présent, nous n'avons rien envisagé qui soit significativement différent de l'exemple du lecteur de nouvelles présenté dans le guide du développeur Android. La seule différence majeure est d'avoir trois fragments au lieu de deux.

Maintenant, le cas des onglets de 7 pouces qui ne peuvent accueillir que 2 fragments. Comment cela fonctionne-t-il ? Notez qu'il y a deux combinaisons possibles ici :

  1. Frag1 et Frag2 sont affichés.
  2. Frag2 et Frag3 sont affichés.

Je n'arrive pas à m'y retrouver. Dois-je faire tout cela dans ActivityA ? Dois-je créer une toute nouvelle activitéD ? Combien de layouts devrais-je créer (j'en ai compté environ 8) ? N'y a-t-il pas trop de permutations ?

Je me rends compte que l'approche à activité unique que j'ai proposée plus haut n'est peut-être pas adaptée à ce scénario, étant donné que l'affichage et le masquage des fragments ne sont pas triviaux en soi.

Avez-vous des suggestions sur la manière de gérer cela sans être submergé par les mises en page et les combinaisons ?

16voto

curioustechizen Points 4841

Le présent La réponse de @Taylor Clark était très instructive. Cependant, il ne s'agissait pas d'un véritable partage d'expérience sur l'utilisation de l'approche de la mono-activité, comme je l'avais demandé dans ma question initiale. J'ai entrepris de modifier l'exemple du lecteur de nouvelles du guide du développeur Android pour utiliser l'approche de la mono-activité et j'ai trouvé une solution viable.

Il reste à savoir quels sont les cas d'utilisation où cette approche est préférable à la méthode de la pluriactivité (ou s'il y a des cas d'utilisation). Par ailleurs, je n'ai pas examiné en détail le scénario à trois volets décrit dans l'édition 1 de ma question.

J'espère publier prochainement l'ensemble de mon projet, mais voici un aperçu rapide de la manière dont je m'y suis pris :

  • Unique Activity : NewsActivity
  • Deux fragments : TitlesListFragment et DetailsFragment
  • Les deux fragments sont toujours présents dans NewsActivity . En fonction de la dualité actuelle, j'affiche/masque le fragment approprié.

Quelques problèmes que j'ai rencontrés :

Désignation d'une présentation comme étant à double volet ou non :

Dans l'exemple original du lecteur de nouvelles, les mises en page à double volet ont une fonction FrameLayout pour avoir tenu les détails de l'actualité. Nous déterminons si nous nous trouvons actuellement dans une disposition à double volet en vérifiant l'existence de cette disposition de cadre.

Cependant, dans ma solution, les deux fragments sont toujours présents dans toutes les mises en page. Je l'ai piraté en incluant un View avec id dualPane et android:visibility="gone" dans les présentations que je veux à double volet et en omettant cette vue dans la présentation à volet unique. Ensuite, il s'agissait de

mDualPane = findViewById(R.id.dualPane)!=null;

EDIT :

Il y a de meilleures façons de désigner un double panneau que d'avoir une vue factice. Je préfère créer une ressource booléenne. Par exemple, j'ai une ressource config.xml comme suit :

<resources>
    <bool name="dual_pane">false</bool>
</resources>

Je peux alors placer des config.xml dans des dossiers tels que values-xlarge-land , values-port ou values-sw600dp etc. et ajuster la valeur booléenne à true ou false comme je le souhaite.

Ensuite, dans le code, il s'agit de getResources().getBoolean(R.bool.dual_pane);

Fermeture du fragment de détail

Il s'agit d'un problème de différenciation entre les Activity se ferment et le Fragment proche. En fin de compte, j'ai dû passer outre onBackPressed() comme suit :

  • En mode double volet, il suffit d'appeler super.onBackPressed() ;
  • En mode monofenêtre, si nous sommes en TitlesListFragment , appeler super.onBackPressed() ;
  • En mode monofenêtre, si nous sommes en DetailsFragment et l'assimiler à la fermeture du fragment. Cela signifie qu'il est masqué et que le TitlesListFragment .

Ce n'est pas la solution idéale, mais c'est la meilleure que j'aie trouvée.

EDIT :

Suite à la suggestion de @SherifelKhatib dans les commentaires, il existe une façon beaucoup plus propre de gérer les pressions sur le bouton arrière : Il suffit d'ajouter à la pile arrière des fragments la transaction d'affichage/masquage du fragment des détails. Ainsi, lorsque vous appuyez sur le bouton retour, la transaction du fragment est inversée. Vous pouvez également retirer la pile arrière manuellement si vous souhaitez le faire pour d'autres clics de bouton.

10voto

Taylor Clark Points 471

En général, les applications sont divisées en activités parce que chacune représente une "chose" spécifique qu'un utilisateur peut faire. Par exemple, dans une application de courrier électronique, un ensemble défini d'actions pourrait être :

  1. Consultation d'une liste de messages
  2. Consulter les détails d'un message
  3. Rédaction d'une réponse à un courriel.

Chaque action pourrait être sa propre activité qui montrerait un seul (ou un ensemble) de fragments. Toutefois, si vous disposez de l'espace nécessaire à l'écran, il serait judicieux de combiner l'affichage d'une liste de messages ET le détail des messages dans une seule activité qui peut afficher/masquer le fragment "vue détaillée". En fait, les fragments vous permettent de montrer à l'utilisateur plusieurs "activités" en même temps.

Les éléments à prendre en compte pour prendre votre décision :

  1. Les fragments spécifiés dans xml ne peuvent pas être fournis comme arguments
  2. Si votre décision est basée sur l'orientation de l'écran, vous pouvez toujours utiliser des qualificatifs de ressources pour indiquer une autre mise en page avec plus ou moins de fragments (par exemple, mise en page-land-large).
  3. Les fragments ne peuvent pas être maintenus Activités
  4. Les fragments travaillent-ils ensemble pour offrir à l'utilisateur une expérience rationalisée ?
  5. Y a-t-il un moment où l'un de vos fragments disparaîtra définitivement ? Si c'est le cas, il est peut-être temps de créer une nouvelle activité.
  6. Suivez votre instinct. S'il est "naturel" pour vous d'échanger des fragments, ne vous en privez pas. Rappelez-vous simplement que si vous le faites souvent, une activité séparée est peut-être une solution plus appropriée.

J'ai généralement utilisé l'approche des "fragments multiples" pour les versions tablettes des applications et l'approche "un fragment par activité" pour les téléphones, ce qui semble correspondre à ce que vous proposez. première approche répertoriée . Ce n'est pas que le second n'ait pas sa place et son temps, mais je pourrais voir la mise en œuvre devenir rapidement désordonnée !

Désolé pour cette réponse verbeuse ! Peut-être pourriez-vous nous en dire plus sur votre cas d'utilisation spécifique ? J'espère que cela vous aidera !

Réponse à la question Edit One


Voici comment j'imagine que votre projet d'application pourrait être mis en place :

Fichiers sources :

votreapp.package.phone : NewsActivity1, NewsActivity2, NewsActivity3

yourapp.package.tablet : NewsMultipaneActivity

Ressources

mise en page/

activity_news.xml- phone version, only includes Fragment1
activity_news_detail.xml- phone version, only includes Fragment2
activity_news_<something>.xml- phone version, only includes Fragment3

layout-large/

activity_news.xml- 7" tablet version, includes Fragment2 and an empty fragment container. Split vertically

aménagement-grande-terre/

activity_news.xml- same as layout-large, but with the split being horizontally

layout-xlarge-land/

activity_news.xml- 10"+ tablet version, contains all three fragments split horizontally

Que se passe-t-il alors ?

  • Si votre application fonctionne sur un téléphone, lancez NewsActivity1
  • Si votre application fonctionne sur une tablette, lancez NewsMultipaneActivity.

Android échangera les mises en page pour vous, en fonction de la taille et de l'orientation de l'écran, tant que les noms de fichiers sont identiques. Étant donné que Fragment2 sera toujours affiché, vous pouvez le "coder en dur" dans les présentations de votre tablette. Vous pouvez ensuite utiliser FragmentTransactions pour passer de Fragment1 à Fragment3 dans le conteneur si nécessaire

Ne manquez pas de consulter http://developer.Android.com/guide/topics/resources/providing-resources.html#AlternativeResources pour voir comment vous pouvez tirer parti des qualificateurs de ressources pour atténuer certains des problèmes liés aux différents écrans et aux différentes orientations.

1voto

Lic Points 267

Dans cet article http://developer.Android.com/guide/practices/tablets-and-handsets.html#Fragments Google dit :

"L'approche que vous choisissez dépend de votre conception et de votre personnalité. personnelles".

et

"Dans d'autres cas, cependant, l'échange dynamique de fragments pour votre téléphone portable est une bonne chose. peut rendre votre code plus compliqué, parce que vous devez gérer toutes les combinaisons de fragments dans le code de l'activité (plutôt que d'utiliser d'autres ressources de mise en page pour définir les combinaisons de fragments) et gérer vous-même la pile arrière de fragments (au lieu de permettre à la pile de fragments la pile normale de l'activité pour gérer la navigation arrière)".

1voto

smok Points 831

Merci pour cette question et pour vos conseils. J'ai utilisé l'approche multi-activités jusqu'à ce que je rencontre un problème. Mon application ressemble au lecteur de nouvelles de l'exemple de document. Considérez ce scénario :

  1. (état initial) J'utilise une tablette en mode paysage (deux volets), l'activité A affiche une liste d'articles à gauche et quelques articles à droite.
  2. Je fais pivoter l'appareil, l'activité A est maintenant en mode volet unique et affiche une liste d'articles.
  3. Je clique sur un élément de la liste, l'activité B démarre avec l'aritcle ouvert.
  4. Maintenant, je fais pivoter l'appareil en mode paysage.

Que se passe-t-il ? L'activité B affiche un article en taille réelle, alors que je souhaite revenir à deux volets. Je ne sais pas trop comment résoudre ce problème. Bien sûr, l'activité B peut vérifier le mode multi-volets et se terminer elle-même, et l'activité A peut vérifier quel était le dernier article affiché... C'est moche. Qu'en pensez-vous ?

PS J'ai l'impression que l'application GMail utilise une approche mono-activité. Je ne vois aucune transition d'activité lorsque je sélectionne un e-mail dans la liste. Elle se comporte également correctement dans le scénario que j'ai décrit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X