Как я должен структурировать файл макета при реализации многоосевых конфигураций (например, master-detail) в одной архитектуре действия?

В настоящее время я переключаюсь на single activity architecture, который будет управлять загрузкой фрагментов в и из container layout. Все идет хорошо, но я попал в ловушку. Я хочу реализовать шаблон master-detail, но я не могу найти лучший способ обработки файла макета. Есть два метода, о которых я думал, но оба имеют последствия, которые мне либо не нравятся, либо они не уверены.

  • отдельный файл layout-land со вторым контейнером: проблема заключается в том, что я не хочу, чтобы второй контейнер занимал место, когда я не располагаюсь в конфигурации с несколькими фрагментами, поэтому я просматриваю много параметров программного макета изменения, которые могут стать беспорядочными.
  • nested fragments: я мог бы загрузить специальный фрагмент multi-configuration, формат XML которого содержит соответствующие фрагменты, вложенные в

В основном я ищу некоторые рекомендации о том, какой подход я должен принять, будь то два варианта, которые я упомянул, или другой метод, который я пропускаю.

Изменить: Я собрал рисунок Google, который иллюстрирует две идеи, которые у меня были до сих пор.

Ответ 1

Позвольте сломать вопрос в пару частей:

1) Какой тип устройства используется? (например, планшет или телефон)

2) Если я телефон, какая у меня ориентация?

Чтобы определить, работаете ли вы на планшете или телефоне, вы можете использовать ведро sw800dp (надеюсь, они не придумают телефон шириной 800dp), чтобы позволить раме раздувать макет, если ширина устройства как минимум 800 дп. Этот файл макета будет содержать либо 2 статических Fragments, либо два контейнера (ViewGroups для динамического размещения Fragments). Вы можете выяснить, находитесь ли вы в конфигурации "планшета", если попытка захвата одного из двух Fragments или двух ViewGroups не возвращает null.

Если вы получаете null, тогда вы знаете, что ваше устройство является телефоном. Вы можете определить, находитесь ли вы в режиме пейзажа или портрета, используя getResources().getConfiguration().orientation.

Ответ 2

EDIT: Из обсуждения в комментариях я вижу, что ваша основная проблема, похоже, связана с изменением ориентации.

  • Как сказал Эммануэль, когда произошло изменение конфигурации (и вы в основном вернуться к onCreate(), вам нужно проверить getResources().getConfiguration().orientation. В соответствии с этим, вам нужно проверить, нужно ли удалять или добавлять фрагменты/с. Так, например, у вас есть смартфон в портрете, только один фрагмент присутствует. Затем вы переходите в ландшафт, вы должны либо

    • добавить фрагмент в старый макет или
    • удалить весь стек фрагмента и добавить новый макет
  • Невозможно справиться с изменениями параметров макета (например, установить видимость с GONE на VISIBLE и т.д.), если вы хотите использовать старый макет для вашего контейнера фрагментов. Если вы не используете свой старый макет и не создаете новый, вам нужно сохранить состояние пользовательского интерфейса, чтобы пользователь получил его выбор и т.д. Назад (вы знаете, что этот материал, вероятно, использует намерения и т.д.).

Я предпочитаю создавать новый макет для новой конфигурации и воссоздавать состояние, поэтому я делаю что-то вроде этого в onCreate():

if (CheckApp.isScreenBig()) {
        setContentView(R.layout.frag_multi);
    } else {
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            // search and remove former fragments, if there were any
            setContentView(R.layout.frag_multi);
        } else {
            if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
                getSupportFragmentManager().beginTransaction().add(android.R.id.content, new FragSingle()).commit(); // single Fragment
            }
        }
    }

Обнаружение многоконфигурации, например, Определите, является ли устройство смартфоном или планшетом?

В своей деятельности запустите свои настройки в onCreate

if (App.isScreenBig()) {
        setContentView(R.layout.frag_multi);
    } else {
        if (getSupportFragmentManager().findFragmentById(android.R.id.content) == null) {
            getSupportFragmentManager().beginTransaction().add(android.R.id.content, new FragMainPaging()).commit(); // single Fragment
        }
    }

В зависимости от вашего общего дизайна вам больше не нужно ничего делать. Если вам нужно взаимодействовать между вашими фрагментами, вы можете распространять изменения через свой родительский фрагмент /Activity ViewPager или контроллер или все, что у вас есть.

Обычно я использую вложенные фрагменты и использую что-то подобное для обмена изменениями

((FragManagedPaging) getParentFragment()).forwardChanges(NotifyState.NOTIFY_ALL, result);

NotifyState - это перечисление, указывающее, является ли изменение релевантным для всех фрагментов или некоторых (я передаю имена классов, если я хочу определенные), или если я хочу создать новый фрагмент для определенного события (NotifyState.ADD) и т.д. В родительском фрагменте размещаются другие фрагменты (также, если необходимо, ViewPager) и форвардные изменения, если есть другие фрагменты. Другие фрагменты имеют метод уведомления, который указывает на работу.

void onChangeOccurred(Object... args) {
// look what changed, what work to do in args, etc.

Но в целом это решать вам.

Пример многоуровневой компоновки:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:baselineAligned="false"
    android:orientation="horizontal" >

    <fragment
        android:id="@id/frag_travel_list"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="2"
        class="de.einschnaehkeee.travel.check.frag.FragTravelBags" />

    <fragment
        android:id="@id/frag_travel_items"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="3"
        class="de.einschnaehkeee.travel.check.frag.FragBag" />

    <fragment
        android:id="@id/frag_choose_items"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="3"
        class="de.einschnaehkeee.travel.check.frag.ChooseItemsFragment" />

</LinearLayout>

Для конфигураций с макетами с несколькими панелями используйте соответствующие каталоги макетов, например layout-land/frag_multi.xml и т.д.