32

Я хотел настроить переход общего элемента при переходе от одного действия к другому.Переход активности активного элемента на андроид 5

Первая активность имеет RecyclerView с элементами. Когда элемент щелкнут, этот элемент должен анимироваться для нового действия.

Итак, я установил андроид android: transitionName = "item" как для последних видов активности, так и для просмотров элементов вида ресайклеров.

Я также использую этот код при переходе к следующей деятельности:

this.startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, itemView, "boomrang_item").toBundle()); 

При щелчке элемента, он переходит правильно и новый вид показан. Это действительно приятно. Однако, когда я нажимаю кнопку «Назад». Иногда это работает, но большую часть времени мои аварии активности со следующим StackTrace:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.ViewGroup.transformMatrixToGlobal(android.graphics.Matrix)' on a null object reference 
      at android.view.GhostView.calculateMatrix(GhostView.java:95) 
      at android.app.ActivityTransitionCoordinator$GhostViewListeners.onPreDraw(ActivityTransitionCoordinator.java:845) 
      at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:847) 
      at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1956) 
      at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1054) 
      at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5779) 
      at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) 
      at android.view.Choreographer.doCallbacks(Choreographer.java:580) 
      at android.view.Choreographer.doFrame(Choreographer.java:550) 
      at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) 
      at android.os.Handler.handleCallback(Handler.java:739) 
      at android.os.Handler.dispatchMessage(Handler.java:95) 
      at android.os.Looper.loop(Looper.java:135) 
      at android.app.ActivityThread.main(ActivityThread.java:5221) 
      at java.lang.reflect.Method.invoke(Native Method) 
      at java.lang.reflect.Method.invoke(Method.java:372) 
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899) 
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694) 

Что я делаю неправильно? Похоже на ошибку в android 5

+0

Вы могли бы добавить все соответствующие коды, чтобы было легче выяснить, куда вы идете неправильно? – gaara87

+0

Попробуйте установить 'transitionName' на _only_ представлениях общего элемента. –

+0

У меня такая же проблема, когда я открываю новое действие, поворачиваю экран и нажимаю кнопку «Назад». Любые решения? – jclova

ответ

3

Если вы используете Proguard, попробуйте добавить это в свой файл правил. У меня была такая же проблема, и она работает?

-keep public class android.app.ActivityTransitionCoordinator

2

Убедитесь, что «itemView» вы передаете в переходе вида щелкнул (получил на свой OnClick() обратный вызов)

4

Попробуйте удалить любые слияния XML-тег, которые вы могли бы иметь на вид окончательной деятельности. Я заметил, что переход к представлению, содержащему тег merge, в котором переходный элемент является прямым дочерним элементом тега merge, вызовет эту ошибку, но следует заменить тег merge другим контейнером, например CardView, анимацией работает просто отлично. Также убедитесь, что между именами transitionNames в представлениях существует соотношение 1: 1.

ОБНОВЛЕНИЕ: Я повторил эту проблему еще раз при выполнении перехода активности, нажав кнопку «Назад», чтобы вернуться к первоначальной активности, а затем повторю попытку перехода. Я обращался к прямому родительскому «компоненту перехода», (A RelativeLayout) по id, с вызовом findViewById(), а затем вызывал removeAllViews(). Я закончил тем, что менял код, чтобы вызвать 'removeAllViews()' на более высоком предке, чем родительский, также удалил тег из элемента, который должен был заменить «переходный компонент» после загрузки страницы. Это облегчило мою проблему.

7

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

Мой обходной путь, чтобы удалить обратный переход (во 2-й деятельности), если экран повернут, прежде чем вернуться, но я уверен, что там должен быть лучший способ справиться с этим:

@Override 
public void onConfigurationChanged(Configuration newConfig) { 
    super.onConfigurationChanged(newConfig); 
    mOrientationChanged = !mOrientationChanged; 
} 

@Override 
public void supportFinishAfterTransition() { 
    if (mOrientationChanged) { 
     /** 
     * if orientation changed, finishing activity with shared element 
     * transition may cause NPE if the original element is not visible in the returned 
     * activity due to new orientation, we just finish without transition here 
     */ 
     finish(); 
    } else { 
     super.supportFinishAfterTransition(); 
    } 
} 
3

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

+0

Это было решение! –

1

То, что я придумал, заключается в том, чтобы не переходить к Activity с RecyclerView или не менять переход с чем-то другим.

Отключить все обратные переходы:

@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
@Override 
public void finishAfterTransition() { 
    finish(); 
} 

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

// Track if finishAfterTransition() was called 
private boolean mFinishingAfterTransition; 

@Override 
protected void onCreate(@Nullable final Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    mFinishingAfterTransition = false; 
} 

public boolean isFinishingAfterTransition() { 
    return mFinishingAfterTransition; 
} 

@Override 
@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
public void finishAfterTransition() { 
    mFinishingAfterTransition = true; 
    super.finishAfterTransition(); 
} 

public void clearSharedElementsOnReturn() { 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
     TransitionUtilsLollipop.clearSharedElementsOnReturn(this); 
    } 
} 

@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
private static final class TransitionUtilsLollipop { 

    private TransitionUtilsLollipop() { 
     throw new UnsupportedOperationException(); 
    } 

    static void clearSharedElementsOnReturn(@NonNull final BaseActivity activity) { 
     activity.setEnterSharedElementCallback(new SharedElementCallback() { 

      @Override 
      public void onMapSharedElements(final List<String> names, 
        final Map<String, View> sharedElements) { 
       super.onMapSharedElements(names, sharedElements); 
       if (activity.isFinishingAfterTransition()) { 
        names.clear(); 
        sharedElements.clear(); 
       } 
      } 
     }); 
    } 

С, что реализуется в базовую деятельность, вы можете легко использовать ее в onCreate()

@Override 
protected void onCreate(@Nullable final Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    clearSharedElementsOnReturn(this); 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
     // set your own transition 
     getWindow().setReturnTransition(new VerticalGateTransition()); 
    } 
} 
1

У меня было это ошибка, моя была вызвана теми же соображениями позади ответа гидры, но была вызвана клавиатурой, скрывающей общий элемент, к которому переход возвращался.

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

View view = this.getCurrentFocus(); 
if (view != null) { 
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 
    imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 
} 
supportFinishAfterTransition(); 
2

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

Transition sharedElementExitTransition = getWindow().getSharedElementExitTransition(); 
     if (sharedElementExitTransition != null) { 
      sharedElementExitTransition.addListener(.....); 
     } 

В качестве последней меры, хотя я не уверен, если это сделал разницу, я также сделал recyclerView.setLayoutFrozen(true)/recyclerView.setLayoutFrozen(false) в onTransitionStart/onTransitionEnd.

1

Как указано @Fabio Rocha, убедитесь, что itemView извлечен из ViewHolder.

Вы можете получить ViewHolder по положению с помощью

mRecyclerView.findViewHolderForAdapterPosition(position); 
0

Причина этого на самом деле довольно проста: При переходе обратно в родительскую активность или фрагмента, Посмотреть еще не там (может по многим причинам).
Итак, что вы хотите сделать, это отложить переход на переход до просмотра.

Моя работа вокруг, чтобы вызвать следующую функцию в OnCreate() в моем фрагменте (но работает в деятельности тоже):

private void checkBeforeTransition() { 
    // Postpone the transition until the window's decor view has 
    // finished its layout. 
    getActivity().supportPostponeEnterTransition(); 

    final View decor = getActivity().getWindow().getDecorView(); 
    decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
     @Override 
     public boolean onPreDraw() { 
      decor.getViewTreeObserver().removeOnPreDrawListener(this); 
      getActivity().supportStartPostponedEnterTransition(); 
      return true; 
     } 
    }); 
} 
0

Я сталкивался с такой же вопрос, на самом деле я использовал firebase и У меня есть список информации, и когда пользователь нажимает на него, он будет вызывать detailActivity с sharedAnimation в этом действии. Я обновлял его, как видно, используя firebase, поэтому событие firebase обновляло элемент списка, как видно, в этом случае эта проблема вызывает, поскольку просмотр ресайклера этого экрана макет.

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

onPause() Я заморозил макет и onResume() установил его как false;

@Override 
public void onPause() { 
    super.onPause(); 
    mRecycler.setLayoutFrozen(true); 
} 

@Override 
public void onResume() { 
    super.onResume(); 
    mRecycler.setLayoutFrozen(false); 
} 

И это работает.