Как написать многопользовательское приложение Android с очень глубокой навигацией
TL; ДР:
Как многоуровневые приложения с глубокой навигацией, похожими на приложение Spotify iPad, выглядят и работают на Android, и как это реализовать?
Длинная версия:
Я работаю над приложением, где пользователь видит списки элементов и затем может углубиться в эти элементы. Эти страницы подробностей элементов могут снова открывать списки связанных элементов, которые, в свою очередь, содержат подробные страницы и т.д. В качестве приложения для телефона это будут отдельные действия, которые могут выглядеть и связываться друг с другом следующим образом:
![User clicks on Item#2 in Overview and gets the detail page, then clicks on "List of things" there]()
![Here, 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 layout]()
![The user selects Item #2, and the item detail page opens on the right pane]()
![On 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 pane]()
![A 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/...