Дизайн фрагментов: адаптация к нескольким макетам экрана путем отображения / скрытия фрагментов в рамках одного действия?



Я пытаюсь понять, как использовать фрагменты для создания приложений, которые хорошо адаптируются к нескольким экранам и макетам. Я изучил несколько примеров:




  1. в фрагментов документ на руководство разработчика Андроид.


  2. Google IO app

  3. фрагменты образца изActionBar Sherlock .


Все они поддерживают множественный подход Activity:




  • на большом экране отобразите один Activity с несколькими Fragments

  • на экране меньшего размера, разделить Fragmentс несколькими Activity ' ы.


Я подумал о другом подходе-единственном Activity:




  • есть один Activity со всеми Fragment s в нем.

  • в зависимости от размера и ориентации экрана, Показать / Скрыть соответствующие Fragment (с помощью FragmentTransaction.show() / FragmentTransaction.hide()) .


Чтобы проиллюстрировать тот же пример "список новостных статей / содержание статей", который использует руководство разработчика Android:




  • имейте News деятельность, содержащая как ArticleListFragment, так и ArticleReaderFragment.

  • на вкладке всегда отображаются оба фрагмента.

  • в телефоне ArticleReaderFragment изначально скрыто. Когда статья выбирается из списка, ArticleListFragment скрывается, а ArticleReaderFragment отображается.


Кто-нибудь использовал подобный подход? Есть ли какие-либо практические недостатки у этого метода? Кажется ли это лучше / хуже по сравнению с способом множественной активности? Например, фрагменты не могут быть показаны / скрыты в XML-one должен использовать FragmentTransaction для этого.





Правка 1: Описание гипотетического сценария



Представьте себе приложение, которое может отображать на экране одновременно до трех "панелей". Далее, необходимо учитывать следующие факторы:


  • телефон может одновременно отображать только одну панель (независимо от книжной/альбомной ориентации)

  • 7-дюймовый планшет может отображать 2 панели, разделенные вертикально в портретном и горизонтально в альбомном режиме.
  • 10+ дюйм планшет может отображать 2 панели, разделенные вертикально в портретной ориентации; 3 панели, разделенные горизонтально в альбомной ориентации.


Для простоты давайте не будем включать в обсуждение телевизионные экраны.



Теперь, переводя это на дизайн:



    У нас есть три фрагмента: Фраг1, Фраг2 и Фраг3.
    В простейшем случае все три фрагмента находятся в одной активности (назовем ее ActivityA). Это 10-дюймовый ландшафтный корпус.
  • другой "простой" случай, когда каждый фрагмент находится в его собственная активность-ActivityA содержит Frag1; ActivityB содержит Frag2 и ActivityC содержит Frag3.


До сих пор мы не рассматривали ничего, что существенно отличалось бы от примера News Reader, представленного в руководстве разработчика Android. Единственное существенное отличие состоит в наличиитрех фрагментов вместо двух.

Теперь, случай 7-дюймовых вкладок, которые могут вместить только 2 фрагмента. Как это будет работать? Обратите внимание, что здесь возможны две комбинации:




  1. отображаются Фраг1 и Фраг2.

  2. отображаются Фраг2 и Фраг3.


Я просто не мог обернуть мою голову вокруг этого. Делаю ли я все это в рамках ActivityA? Могу ли я просто создать совершенно новую ActivityD? Сколько макетов мне нужно будет создать (я насчитал около 8)? Не слишком ли много перестановок?



Я понимаю, что подход с одной активностью, который я предложил выше, также может не подходить для этого сценария - так как показывать / скрывать фрагменты сами по себе нетривиальны.



Какие-нибудь предложения о том, как справиться с этим, не перегружаясь макетами и комбинациями?

553   4  

4 ответов:

Этот ответ @Taylor Clark был довольно информативным. Однако это не было фактическим обменом опытом с использованием подхода с одной активностью, как я задал в своем первоначальном вопросе. Я решил изменить пример чтения новостей из руководства для разработчиков Android, чтобы использовать подход с одной активностью, и придумал работоспособное решение.

Остается выяснить, в каких случаях этот подход предпочтительнее метода множественной активности (или предпочтительнее ли он вообще). есть такие случаи вообще). Кроме того, я не рассматривал подробно сценарий 3-панели, описанный в правке 1 моего вопроса.

Я надеюсь опубликовать весь свой проект в ближайшее время, но вот краткий обзор того, как я это сделал:

  • Сингл Activity: Новостная Активность
  • два фрагмента: TitlesListFragment и DetailsFragment
  • оба фрагмента всегда присутствуют в NewsActivity. В зависимости от текущего состояния двойной панели, я показываю/скрываю соответствующий фрагмент.

Некоторые проблемы I наткнулся:

Обозначение макета как двухпанельного или нет:

В оригинальном примере программы чтения новостей двухпанельные макеты имеют FrameLayout для хранения сведений о новостях. Мы выясняем, находимся ли мы в настоящее время в макете с двумя панелями, проверяя наличие этого макета фрейма.

Однако в моем решении оба фрагмента всегда присутствуют во всех макетах. Я взломал это, включив View с id dualPane и android:visibility="gone" в те макеты, которые я хочу быть двухпанельными и опустить это представление в однопанельном макете. Тогда это был вопрос

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

Редактировать:

Есть лучшие способы обозначить двойную панель, чем иметь фиктивный вид. Я предпочитаю создать логический ресурс. Например, у меня есть config.xml следующим образом:

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

Затем я могу поместить дополнительные файлы config.xml в папки, такие как values-xlarge-land, values-port или values-sw600dp и т. д. и измените логическое значение на true или false, как я хочу.

Затем, в код это дело getResources().getBoolean(R.bool.dual_pane);

Закрытие фрагмента деталей

Это была проблема дифференциации между Activity близким и Fragment близким. В конце концов, мне пришлось переопределить onBackPressed() следующим образом:
  • в режиме двойной панели просто вызовите super.onBackPressed();
  • в однопанельном режиме, если мы находимся в TitlesListFragment, вызовите super.onBackPressed();
  • в однопанельном режиме, если мы находимся в DetailsFragment, то рассматриваем это как закрытие фрагмента. Это значит спрятать его и показать TitlesListFragment.
Это не идеально, но это лучшее, что я мог придумать.

EDIT:

Основываясь на предложении @SherifelKhatib в комментариях, есть гораздо более чистый способ обработки нажатий кнопок Назад: просто добавьте к фрагменту backstack, транзакцию показа / скрытия фрагмента деталей. Таким образом, когда вы нажимаете кнопку Назад, транзакция фрагмента отменяется. Вы также можете открыть backstack вручную, если вы хотите сделать это на других нажатие кнопки.

Обычно приложения разделяются на действия, потому что каждое из них представляет определенную "вещь", которую может сделать пользователь. Например, в почтовом приложении определенный набор действий может быть следующим:

  1. просмотр списка сообщений
  2. просмотр подробностей сообщения
  3. составление ответа на электронное письмо.
Каждое действие может быть своей собственной активностью, которая показывает один (или множество) фрагментов. Однако, если бы у вас был экран недвижимости, было бы разумно объединить просмотр список сообщений и детали сообщения в одно действие, которое может показать / скрыть фрагмент "детального представления". По сути, фрагменты позволяют показать пользователю несколько "действий" одновременно.

Что следует учитывать при принятии решения:

  1. фрагменты, указанные в xml, не могут быть представлены аргументами
  2. Если ваше решение основано на ориентации экрана, вы всегда можете использовать квалификаторы ресурсов, чтобы указать на другой макет с большим/меньшим количеством фрагментов (напр. планировка-Земля-большая)
  3. фрагменты не могут быть поддержаны деятельностью
  4. работают ли фрагменты вместе, чтобы обеспечить пользователю оптимизированный опыт?
  5. Есть ли время, когда один из ваших фрагментов исчезнет навсегда? Если да, то, возможно, пришло время для новой деятельности
  6. действуй своим чутьем. Если его "естественное" для вас применение для замены фрагментов, идите на это. Просто помните, что если вы обнаружите, что делаете это много, возможно, отдельное занятие будет более подходящим. решение

Обычно я использую "подход с несколькими фрагментами" для планшетных версий приложений и "один фрагмент на действие" для телефонов, который звучит в соответствии с вашим первым подходом, перечисленным. Не то чтобы у второго не было времени и места, но я мог видеть, что реализация быстро запутывается!

Извините за многословный ответ! Возможно, вы могли бы рассказать больше о вашем конкретном случае использования? Надеюсь, это поможет!


Реакция на Вопрос Edit One


Вот как я представляю себе ваш проект приложения:

Исходные файлы:

Yourapp.пакет.телефон: NewsActivity1, NewsActivity2, NewsActivity3

Yourapp.пакет.таблетка: NewsMultipaneActivity

Ресурсы

Макет /

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

Макет-Большой/

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

Планировка-большая земля /

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

Макет-xlarge-land /

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

Так что же здесь происходит?

  • Если ваше приложение работает на телефоне, запустите NewsActivity1
  • Если ваше приложение работает на планшете, запустите NewsMultipaneActivity

Android будет менять макеты для вас, основываясь на размере экрана и ориентации, пока имена файлов одинаковы. Поскольку Fragment2 всегда будет отображаться, вы можете "жестко закодировать" его в макеты вашего планшета. Затем вы можете использовать FragmentTransactions для переключения между Fragment1 и Fragment3 в контейнере по мере необходимости

Обязательно проверьте http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources чтобы увидеть, как вы можете использовать преимущества квалификаторов ресурсов для смягчения некоторых головных болей различных экранов и ориентаций

Благодарю вас за этот вопрос и ваши идеи. Я использовал подход множественной активности, пока не столкнулся с проблемой. Мое приложение-это как док-пример чтения новостей. Рассмотрим следующий сценарий:

  1. (начальное состояние) я использую планшет в ландшафтном режиме (две панели), действие а отображает список статей слева и некоторые статьи справа.
  2. я поворачиваю устройство, теперь действие а находится в однопанельном режиме и отображает список статей.
  3. я нажимаю на элемент списка, действие B начинается с открытого aritcle.
  4. Теперь я поворачиваю устройство обратно в ландшафтный режим.

Что происходит? Упражнение B показывает статью в натуральную величину, в то время как я, конечно, хочу вернуться к двум панелям. Я не знаю, как решить эту проблему красиво. Конечно, действие B может проверить наличие режима с несколькими панелями и закончить само, а действие A может проверить, что было отображено в последней статье... Это выглядит некрасиво. Мысли?

PS у меня есть подозрение, что приложение GMail использует подход с одной активностью. Я не вижу никакого перехода активности, когда я выбираю электронную почту из списка. Он также ведет себя правильно в описанном мною сценарии.

В этой статье http://developer.android.com/guide/practices/tablets-and-handsets.html#Fragments Google говорит:

"подход, который вы выберете, зависит от вашего дизайна и личных качеств. предпочтения."

И

" в других случаях, однако, динамическая замена фрагментов для вашего телефона дизайн может сделать ваш код более сложным, потому что вы должны управлять все комбинации фрагментов в коде действия (вместо использования альтернативная компоновка ресурсы для определения комбинаций фрагментов) и управляйте задним стеком фрагментов самостоятельно (вместо того, чтобы позволять обычный стек активности для обработки обратной навигации)."

Comments

    Ничего не найдено.