Как написать многопользовательское приложение Android с очень глубокой навигацией

TL; ДР: Как многоуровневые приложения с глубокой навигацией, похожими на приложение Spotify iPad, выглядят и работают на Android, и как это реализовать?

Длинная версия: Я работаю над приложением, где пользователь видит списки элементов и затем может углубиться в эти элементы. Эти страницы подробностей элементов могут снова открывать списки связанных элементов, которые, в свою очередь, содержат подробные страницы и т.д. В качестве приложения для телефона это будут отдельные действия, которые могут выглядеть и связываться друг с другом следующим образом: User clicks on Item#2 in Overview and gets the detail page, then clicks on "List of things" thereHere, List of Things is open, and the user opts to see "Thing #3"

В макетах пользователь видит начальный обзор, а затем выбирает "Item # 2" из первого списка. Открывается новая активность, показывающая детали для позиции №2. Здесь он выбирает, чтобы увидеть список вещей, относящихся к Item # 2. В этом новом списке отображается действие openend на третьем рисунке, и щелчок по нему открывает подробности для этой вещи. Он может перемещаться так глубоко в контент, как ему нравится.

Это хорошо работает с обычными действиями в Android. Я работаю над приложением приложения к планшетам и думаю о том, как наилучшим образом реализовать это. План состоит в том, чтобы создать многопанельный макет с той же концепцией. Это очень похоже на то, как работает приложение iPad Spotify (будет интересно посмотреть, как они доводят его до Android после создания табло-специфических макетов).

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

Initial multi-pane tablet layoutThe user selects Item #2, and the item detail page opens on the right paneOn the detail page, the user selects "List of things", and the right pane moves to the left, and the list of things opens in the right paneA click on Thing #3 opens the thing details in the right pane

Я не уверен, как лучше всего реализовать этот шаблон навигации. Многоуровневые приложения с ограниченной навигационной глубиной, такие как GMail, могут быть созданы с помощью статической ViewGroup (LinearLayout будет в порядке), содержащей все фрагменты, и глубже погружаясь в навигацию, заменяет содержимое следующего контейнера вправо и анимирует его (см. Реализация CommonWares этого на SO).

Это говорит о том, что пользовательская группа ViewGroup станет для вас способом. Если он должен отображать подстраницу (т.е. "Список вещей" ), то он создает новый дочерний элемент в ViewGroup, который на половину ширины экрана с фрагментом, а затем прокручивает видимую область, чтобы панель, с которой только что взаимодействовали и новый ребенок виден. Чтобы правильно связать это с FragmentTransaction, чтобы задний стек работал правильно, я бы предположил, что это будет примерно так:

View newPane = container.addChild();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(newPane, new ListOfThingsFragment(2));
ft.remove(paneOnRight, fragmentOnRight);
ft.commit();
container.animateToRight();

Я не вижу способ сделать анимацию внутри FragmentTransaction.

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

Ответ 1

Мы столкнулись с той же проблемой с нашим приложением. Ограничения, которые мы дали себе:

  • Динамические числа панелей
  • Каждая панель может иметь разный размер.
  • Фрагменты внутри панелей должны быть правильно сохранены при изменении ориентации.

В свете этих ограничений мы построили новый макет, который мы называем PanesLayout. Вы можете проверить это здесь:

https://github.com/cricklet/Android-PanesLibrary

В основном это позволяет легко добавлять любое количество динамически размерных панелей и прикреплять фрагменты к этим панелям. Надеюсь, вы найдете ее полезной!:)

Ответ 2

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

Есть два ключевых инструмента: setCustomAnimations и LayoutTransition Да, насколько я мог это сделать, вам нужно отделить анимацию набора, чтобы заставить его работать.

Итак, давайте перейдем к некоторому коду, вы определите свой XML с горизонтальным LinearLayout и обязательно включите в него следующую строку.

android:animateLayoutChanges="true"

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

Итак, после того, как этот макет завышен, мы собираемся захватить это LayoutTransition и обмануть его в наших потребностях:

LayoutTransition lt = myLinearLayout.getLayoutTransition();
lt.setAnimator(LayoutTransition.APPEARING, null);
lt.setAnimator(LayoutTransition.DISAPPEARING, null);
lt.setStartDelay(LayoutTransition.CHANGE_APPEARING, 0);
lt.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);

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

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

setContentView(R.layout.main); // the layout with that Linear Layout
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.main, frag1, FRAG_1_TAG); // it good to have tags so you can find them later
ft.add(R.id.main, frag2, FRAG_2_TAG);
ft.add(R.id.main, frag3, FRAG_3_TAG);
ft.hide(frag3);
ft.commit();

теперь на транзакции это просто:

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.push_left_in, R.anim.push_left_out, R.anim.push_right_in, R.anim.push_right_out);
Fragment left = getFragmentManager().findFragmentByTag(FRAG_1_TAG);
Fragment right = getFragmentManager().findFragmentByTag(FRAG_3_TAG);

ft.hide(left);
ft.show(right);

ft.addToBackStack(null);
ft.commit();

окончательные примечания:

чтобы сделать более глубокую навигацию, это просто вопрос стрельбы FragmentTransactions, чтобы добавить фрагменты к LinearLayout и hide или detach фрагменту левой стороны.

Также для того, чтобы фрагменты работали над линейным макетом, важно установить их LinearLayout.LayoutParams.weight во время выполнения, что-то похожее на следующий код, применяемый к представлению фрагмента

((LinearLayout.LayoutParams) view.getLayoutParams()).weight = 1;

чтобы заставить его работать на телефонах, а также просто использовать общие шаблоны нескольких экранов.

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

Счастливое кодирование!

Ответ 3

Частичный ответ части анимации: Вы можете выполнять анимацию с помощью FragmentTransaction:

ft.setCustomAnimations(android.R.anim.slide_in_left, 
    android.R.anim.slide_out_right);

Обновление: см. этот ответ от самого Рето Мейера об анимации фрагмента: fooobar.com/info/29348/...