Подтвердить что ты не робот

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

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

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

  • На большом экране отобразите один Activity с несколькими Fragment s
  • На меньшем экране разделите Fragment на несколько Activity s.

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

  • У вас есть один Activity со всеми Fragment в нем.
  • В зависимости от размера и ориентации экрана покажите/скройте соответствующие Fragment (s) (используя FragmentTransaction.show()/FragmentTransaction.hide()).

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

  • Имейте News активность, содержащую как ArticleListFragment, так и ArticleReaderFragment.
  • На вкладке всегда отображаются оба фрагмента.
  • На телефоне ArticleReaderFragment изначально скрыт. Когда статья выбрана из списка, ArticleListFragment скрыт и отображается ArticleReaderFragment.

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


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

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

  • Телефон может отображать только одну панель за раз (независимо от ориентации на портрете/альбомной ориентации).
  • 7-дюймовый планшет может отображать 2 панели, разбивать по вертикали в "Портрет" и разбивать по горизонтали в ландшафтном режиме.
  • Планшет на 10+ дюймов может отображать 2 панели, разделенных вертикально в Portrait; 3 панели разбиты горизонтально в ландшафте.

Для простоты, держите экраны телевизора вне обсуждения.

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

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

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

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

  • Отображаются Frag1 и Frag2.
  • отображаются Frag2 и Frag3.

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Назначение макета как двойного окна или нет:

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

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

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

EDIT:

Есть лучшие способы обозначить двойную структуру, чем наличие фиктивного представления. Я предпочитаю создавать булевский ресурс. Например, у меня есть 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.

Это не идеально, но это лучшее, что я мог придумать.

ИЗМЕНИТЬ

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

Ответ 2

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

  • Просмотр списка сообщений
  • Просмотр сообщения
  • Составление ответа на письмо.

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

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

  • Фрагменты, указанные в xml, не могут быть предоставлены аргументами
  • Если ваше решение основано на ориентации экрана, вы всегда можете использовать квалификаторы ресурсов, чтобы указать на другой макет с более/менее фрагментами (например, макет-земля-большой).
  • Фрагменты не могут быть сохранены. Действия
  • Разделяются ли фрагменты, чтобы предоставить пользователям обтекаемый опыт?
  • Есть ли время, когда один из ваших фрагментов исчезнет навсегда? Если да, возможно, это время для нового действия.
  • Идите со своей кишкой. Если его "естественный" для вас приложение для замены фрагментов, пойдите для него. Просто помните, что если вы обнаружите, что делаете это много, возможно, отдельное мероприятие является более подходящим решением.

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

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


Ответ на вопрос Изменить один


Вот как я могу предположить, что ваш проект приложения можно настроить:

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

yourapp.package.phone: NewsActivity1, NewsActivity2, NewsActivity3

yourapp.package.tablet: 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-земля/

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, чтобы узнать, как вы можете использовать квалификаторы ресурсов для смягчения некоторых головных болей разных экранов и ориентации

Ответ 3

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

  • (начальное состояние) Я использую планшет в ландшафтном режиме (две панели), активность A отображает список статей слева, а часть статьи - справа.
  • Я вращаю устройство, теперь активность A находится в режиме с одной панелью и отображает список статей.
  • Я нажимаю на элемент списка, активность B начинается с открытия aritcle.
  • Теперь я поворачиваю устройство обратно в альбомный режим.

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

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

Ответ 4

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

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

и

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