Ошибка перехода общего элемента в Android Lollipop

Я пытаюсь выполнить переход общих элементов Android 5.0 в ситуации Master Detail из ListView. Я отправляю изображение.

Я столкнулся с ошибкой при переходе входа, когда изображение вообще не перемещается, пока происходит переход основного действия. После загрузки действия Detail изображение запускается в верхнем левом углу экрана и анимируется в его окончательном месте. Обратный переход работает отлично - изображение анимируется из своего детального положения в правильное положение в мастере.

Вот как это выглядит: https://www.youtube.com/watch?v=AzyA8i27qWc < / а>

Я считаю, что правильно настроил разрешения и указал переход:

<item name="android:windowContentTransitions">true</item>        
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>

<!-- specify shared element transitions -->
<item name="android:windowSharedElementEnterTransition">
    @transition/change_image_transform</item>
<item name="android:windowSharedElementExitTransition">
    @transition/change_image_transform</item>

Этот переход определяется как:

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeImageTransform/>
    <changeBounds/>
    <changeTransform/>
</transitionSet>

Я дал двум представлениям один и тот же уникальный атрибут transitionName в зависимости от их позиции в списке.

Я использую makeSceneTransitionAnimation для анимации:

    View photo = (View) adapter.getView(position, null, listView).findViewById(R.id.photo);
    View navigationBar = findViewById(android.R.id.navigationBarBackground);

    ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
            Pair.create(photo, photo.getTransitionName()),
            Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME));

    Bundle extras = new Bundle();
    Patient selectedPatient = patientList.get(position);
    extras.putParcelable("patient", selectedPatient);
    extras.putInt("position", position);

    Intent intent = new Intent(PatientListActivity.this, PatientActivity_.class);
    intent.putExtras(extras);

    startActivity(intent, options.toBundle());

(Я также указываю навигационную панель как общую, чтобы она не исчезла, что отлично работает)

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

super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_patient);

    patient = getIntent().getExtras().getParcelable("patient");
    patient = app.getPatientByName(patient.getName());

    patientPhotoView.setImageDrawable(patient.getPhoto());

    /* Set up transition functionality */
    position = getIntent().getExtras().getInt("position");
    patientPhotoView.setTransitionName("patientPhoto" + position);
    patientNameView.setTransitionName("patientName" + position);

    postponeEnterTransition();
    final ViewTreeObserver observer = getWindow().getDecorView().getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            final ViewTreeObserver observer = getWindow().getDecorView().getViewTreeObserver();
            observer.removeOnPreDrawListener(this);
            startPostponedEnterTransition();
            return true;
        }
    });

В моем действии Detail нет элемента transitionName, но я устанавливаю его в коде. Соответствующая часть входящей активности (Деталь):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PatientActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="200dip"
            android:orientation="vertical"
            android:id="@+id/patient_top_layout">
            <ImageView
                android:id="@+id/patientPhoto"
                android:layout_width="92dip"
                android:layout_height="92dip"
                android:layout_below="@+id/connectionBar"
                android:layout_marginRight="12dip"
                android:layout_marginTop="12dip"
                android:contentDescription="Patient photo"
                android:src="@drawable/ic_profile_default" />
         </RelativeLayout>
    </LinearLayout>
</RelativeLayout

Рад разместить другой соответствующий код. Любые идеи?

Решено

Пользователь Chris P с + страницы Android Development понял это для меня. В моем основном действии в методе onClick у меня было:

View photo = (View) adapter.getView(position, null, listView).findViewById(R.id.photo);

Решением было заменить эту строку на:

View photo = (View) listView.getChildAt(position).findViewById(R.id.photo);

Я предполагаю, что вызов метода getView адаптера был воссозданием самого представления - я предполагаю, что этот метод должен вызываться ТОЛЬКО при первом создании списка.


comment
Есть ли разница, если вы измените @transition/change_image_transform на @transition/change_image_transform? Есть ли разница, если вы измените getWindow().getDecorView() на объект ImageView совместно используемого элемента?   -  person Alex Lockwood    schedule 05.03.2015
comment
Я не понимаю вашего первого предложенного изменения. Я также добавил к вопросу код change_image_transform. Не было никакой разницы, когда я изменил getWindow().getDecorView() на patientPhotoView (после установки названия перехода и фотографии).   -  person clay_to_n    schedule 05.03.2015
comment
Ой, извините. У меня была опечатка. Есть ли разница, если вы измените @transition/change_image_transform на @android:transition/move?   -  person Alex Lockwood    schedule 05.03.2015
comment
Вау, вы сделали свою домашнюю работу! Исходящий Activity работает как надо. Похоже, что входящая активность ведется неправильно. FWIW, атрибут android: windowContentTransitions не подходит - вам нужен android: windowActivityTransitions. Материальные темы автоматически устанавливают для него значение true, так что все в порядке. Как бы то ни было, вы можете опубликовать свой макет для подробного действия?   -  person George Mount    schedule 05.03.2015
comment
Я разместил соответствующие части макета детальной деятельности. Как я упоминал ранее, атрибут transitionName устанавливается в onCreate для подробного представления (я добавил этот код в сообщение). Большое спасибо за помощь!   -  person clay_to_n    schedule 05.03.2015
comment
Можете ли вы опубликовать видео, иллюстрирующее, как выглядит глючный переход? Вы можете использовать функцию захвата экрана Android Studio и относительно быстро загрузить короткое видео на YouTube.   -  person Alex Lockwood    schedule 13.03.2015
comment
Загрузил видео здесь: youtube.com/watch?v=AzyA8i27qWc Еще попробую комментирую большие части моего кода, чтобы найти, что его нарушает. Обновит разрешение, если найду.   -  person clay_to_n    schedule 19.03.2015
comment
Я только что создал репозиторий git с очень простым примером проблемы, которую я до сих пор не решил: github.com/clay-to-n/shared-element-transition-glitch   -  person clay_to_n    schedule 22.03.2015
comment
Нашел решение и добавил к вопросу.   -  person clay_to_n    schedule 25.03.2015


Ответы (1)


Пытался оставить это в комментариях, но это было слишком долго. Я опробовал ваш макет, проблем не возникло. Мне даже не понадобился вызов postponeEnterTransition. Это немного усложняет отладку.

Принцип работы переходов заключается в том, чтобы фиксировать состояние вещей до изменения, а затем после изменения, а затем анимировать разницу. В переходах между действиями изменение «до» извлекается из местоположения на экране и размера общего элемента в вызывающем действии. Затем он применяет эти границы к текущей иерархии представления. Затем он запрашивает макет и фиксирует состояние «после».

Между моментом захвата состояния «до» и «после» существует чувствительный момент. Если макет изменяется по какой-либо причине, так что значения, захваченные в состоянии после, не являются просто ретрансляцией состояния «до», переход будет сброшен. Также возможно внесение изменений в макет сразу после начала Перехода.

Вы используете механизм отложенной загрузки или действительно полностью загружаете пациента в вызове onCreate? Вы в это время также устанавливаете все окружающие ценности? Я вижу, что у вас есть:

        <ImageView ...
            android:layout_below="@+id/connectionBar"
            ... />

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

person George Mount    schedule 05.03.2015
comment
Спасибо за ответ. Думаю, я собираюсь попытаться вырезать части своего кода, пока не выясню, что вызывает ретрансляцию, если она есть. Я постараюсь подробно рассказать о своих выводах, чтобы помочь другим, когда решу эту проблему. - person clay_to_n; 10.03.2015
comment
Я воссоздал свои обстоятельства из простого проекта, но все равно получаю сбой. Мне где-то что-то не хватает - может быть, у меня странный адаптер массива? Если проблема в реле, я не знаю, где это произойдет, поскольку больше ничего не происходит. Вот он: github.com/clay-to-n/shared- элемент-переход-глюк - person clay_to_n; 22.03.2015
comment
Решил проблему и добавил решение вопроса. Спасибо за помощь. - person clay_to_n; 25.03.2015