Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alpha version Activity transition #27

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

princeparadoxes
Copy link

Доброго времени суток. Я попробовал сделать реализацию Transition между Activity на основе вашей библиотеки. Это в принципе более-менее рабочая версия. Просто хотелось бы услышать ваше мнение о такой реализации.
Суть в том, что мы указываем view содержащий элементы которые нужно анимировать (если не указать берется content). У этой view мы получаем все элементы имеющие id, берем у них параметры нужные для анимации и засовываем все это в Intent. Запускаем новое Activity. На новом Activity на основе пришедших данных формируется FrameLayout. В setContentView мы вставляем этот FrameLayout, создаем сцену для Layout который по идее должен располагаться на этом Activity и вызываем ChangeScene для нее.
С обратным Transition все немного сложнее. При вызове onBackPressed опять создаем FrameLayout на основе пришедших данных, затем находим все элементы из этих данных на текущем экране, берем важные для данного типа view данные (к примеру для ImageView это drawable) и вставляем в наши элементы на FrameLayout. На основе этого FrameLayout формируем сцену и вызываем changeScene.

Еще нужно добавить какой-либо listener по завершению Transition, потому что сейчас завершение Activity делается с помощью postDelayed c отсрочкой равной длительности анимации, это кривой подход и бывает Activity завершается раньше, чем закончилась анимация.

@andkulikov
Copy link
Owner

Приветствую!
Идея и реализация довольно неплохая. Можно пытаться развить идею.
Во первых, про listener по завершению Transition. Это сделать не сложно, у Transition есть addListener и можно подписаться на колбек onTransitionEnd.
Во вторых, я бы вот в какую сторону двигался. Нам при открытии второго активити на самом деле нет смысла прям восстанавливать и выстраивать сцены. Переход от сцены к сцене внутри состоит из снятия нужных для конкретной Transition стартовых параметров, сохранения их в TransitionValues, смены лэйаутов, снятия этих же параметров в финальной сцене и анимированного применения этих изменений. То есть по идее мы должны снять начальные параметры ещё находясь в первой активити, запустить вторую активити, применить новый лэйаут, снять финальные параметры и запустить анимацию. без лишних действий. единственное что нужно дописать, это каким то образом передать информацию во вторую активити о вьюшках, которые были в первой активити, отсутствуют во второй активити и которые необходимо анимировать. чтобы восстановить эти вьюхи и запустить их анимированное пропадание. Это наверно можно сделать дописав captureStartValues у Visibility transition. Сохранять "скриншот" вьюшки в bitmap и передавая его во вторую активити.

@princeparadoxes
Copy link
Author

А почему в качестве координат объекта для аминирования, берутся его координаты внутри его контейнера, а не относительно всего экрана?
Просто получается, что у объекта анимации на первой сцене, контейнер должен быть точно таким же как на второй сцене. Иначе анимация будет глючить.

@andkulikov
Copy link
Owner

Речь идет вероятно о ChangeBounds. Изначально в андроиде он задумывался как анимирующий изменения внутри одного и того же Parent. Потом ему добавили метод setReparent (по умолчанию выключен), в который если проставить true ChangeBounds будет брать координаты как раз относительно всего экрана, а не контейнера. Правда он уже помечен deprecated, потому что в андроид добавили дополнительный транзишн ChangeMatrixTransform, который может помочь отдельно санимировать эту разницу между в координатах parent из первой сцены и из второй сцены. но ChangeMatrixTransform у меня пока так и не получилось бекпортнуть, поэтому пока лучше этот setReparent использовать. То есть тебе сейчас как раз этот режим пригодится по идее

@princeparadoxes
Copy link
Author

Я наверное уже заколебал, но все таки) У меня наконец-то появилось время и я решил сделать как вы и предлагали ("То есть по идее мы должны снять начальные параметры ещё находясь в первой активити, запустить вторую активити, применить новый лэйаут, снять финальные параметры и запустить анимацию."). Собственно с открытием активити никаких проблем нет. А вот с обратной анимацией есть проблемы. Я пошел по самому простому пути и для обратной анимации просто меняю местами mStartValues, mEndValues у Transition который я использовал для анимации открытия. Для того, что бы срабатывало скрывание вьюхи на время анимации я дополнительно меняю местами ссылки на вьюху у стартовых значений и конечных. И тут возникает проблема с теми вьюхами которые есть на этом экране и нет на предыдущем (те которые добавляются в addUnmatched()). Получается, что сама вьюха остается на месте плюс появляется ее анимированная копия.
screenshot_2015-09-30-00-37-34
И вот вроде проблем быть не должно. И я не понимаю из-за чего такой эффект возник.

И еще одна проблема в том, что у Animator нет аналога setFillAfter у Animation. И вот что-то я не смог найти просто способа застыть вьюхи после выполнения анимации. Из-за этого получается моргание на несколько долей секунды. Конечно можно действительно поменять положение у анимируемых вьюх, но может вы знаете способ получше? А то гугление мне не помогло.

@andkulikov
Copy link
Owner

извиняюсь, что так долго отвечал. конечно не заколебал) мне тоже интересно получится ли удобно использовать библиотеку для активити.
про первое: почему так происходит. потому что сама суть таких транзишнов, которые анимируют изменения видимости заключается в том, что вьюшка раньше была, а теперь её нет. и мы анимируем её пропадание. то есть сам транзишн вьюшку не прячет, она уже пропала. а в нашем кейсе она не пропала, так что тут её вручную придется прятать. можно просто setVisibility(View.INVISIBLE) выставить. чтобы отличить такие вью от остальных можно воспользоваться getVisibilityChangeInfo() класса Visibility.
про второе суть та же, на самом деле. ChangeBounds двигает на самом деле не саму вьюшку, а её скриншот, и делает она так как раз потому что включен у ChangeBounds reparentMode. зачем так сделали в андроиде изначально: видимо чтобы если конечный parent меньше в размерах, чтобы уметь анимировать вьюшку вне контейнера parentа. и на самом деле тут не проблема Animator и аналога setFillAfter. тот эффект происходит изза того, что в ChangeBounds написано
anim.addListener(new AnimatorListenerAdapter() {
@OverRide
public void onAnimationEnd(Animator animation) {
ViewOverlayUtils.removeOverlay(sceneRoot, drawable);
ViewUtils.setTransitionAlpha(view, transitionAlpha);
}
});
то есть прячет скриншот и показывает реальную вьюшку, потому что знает что эта вьюшка и должна быть там, куда он скриншот подвинул. а у нас не так получилось.
как эту проблему решить я сходу тоже не могу придумать, подумаю ещё.

@princeparadoxes
Copy link
Author

Ну вроде предыдущие проблемы я поправил. Не очень красиво сделал, но все же. Я в Transition добавил boolean переменную isReverse. И если она true, то немного корректирую поведение Transition пот нужды обратной анимации. Сделал я это под Visibility и ChangeBounds. Вроде они хорошо отрабатывают.
Ну и пока появилось время, я решил начать делать исчезновение тех View которых нет на этом экране. Вы советовали "Это наверно можно сделать дописав captureStartValues у Visibility transition. Сохранять "скриншот" вьюшки в bitmap и передавая его во вторую активити". Я добавил. Прилепил Fade к моему transition иии нечто странное стало происходить. Fade действует абсолютно на все View. Чудеса. Происходящее очень похоже на то как в фильме Матрица, агенты уклонялись от пуль... То есть... Блин... это очень странно выглядит. Хотя в общем и целом они конечно исчезают.
В связи с этим вопрос: можно как то сказать, что "на те view на которые уже зацеплен какой-то Transition - не вешать новых?
А, ну еще эта сволочь не работает в обратную сторону(

@princeparadoxes
Copy link
Author

Короче сохранять скриншот вьюшки в bitmap, что бы после ухода с текущего экрана анимировать появление тех вьюх, что нет на текущем экране - не вариант. Память съедается в нереальных количествах.

@andkulikov
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants