android 5上的共享元素活动转换

android 5上的共享元素活动转换,android,android-animation,android-recyclerview,shared-element-transition,activity-transition,Android,Android Animation,Android Recyclerview,Shared Element Transition,Activity Transition,我想在从一个活动转到另一个活动时设置一个共享元素转换 第一个活动有一个包含项目的RecyclerView。单击某个项目时,该项目应设置为新活动的动画 所以我定了一个目标 android:transitionName=“item”显示在最终活动视图和回收器视图项目视图中 在进行下一个活动时,我也会使用以下代码: this.startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this, itemView, "boomr

我想在从一个活动转到另一个活动时设置一个共享元素转换

第一个活动有一个包含项目的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)
我做错了什么?
如果您使用的是Proguard,那么它看起来像是android 5中的一个bug,请尝试将其添加到您的规则文件中。我也有同样的问题,它看起来有效吗

-保留公共类android.app.ActivityTransitionCoordinator

确保在转换中传递的“itemView”是单击的视图(在onClick()回调中收到)

尝试删除最终活动视图中可能包含的任何合并xml标记。我注意到,转换到包含合并标记的视图(其中转换元素是合并标记的直接子元素)会导致此错误,但如果我使用不同的容器(如CardView)替换合并标记,动画效果会很好。还要确保视图中的transitionNames之间存在1:1的关系

更新:
在执行活动转换时,我再次遇到了这个问题,单击“上一步”按钮返回到初始活动,然后再次尝试转换。我使用findViewById()调用通过id访问“transition component”(一个RelativeLayout)的直接父级,然后调用removeAllViews()。最后,我将代码更改为在比父级更大的父级上调用“removeAllViews()”,并从元素中删除了一个标记,该标记将在页面加载后取代“transition component”。这缓解了我的问题。

我遇到了同样的问题,请注意,如果返回时原始共享元素在上一屏幕上不再可见(可能是纵向屏幕上的最后一个元素,但一旦切换到横向,它就不再可见),则会发生崩溃,因此,转换没有地方可以放回共享元素

我的解决方法是,如果在返回之前屏幕已旋转,则删除返回转换(在第二个活动中),但我确信必须有更好的方法来处理此问题:

@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();
    }
}

确保在第二个活动中转换到的视图不是根布局。
您可以将其包装在一个带有透明窗口背景的框架布局中。

我想到的是避免使用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();
                }
            }
        });
    }

我也犯了同样的错误,我的错误是由hidro的答案背后的相同推理引起的,但是是由于键盘隐藏了转换要返回的共享元素

我的解决方法是在完成活动之前以编程方式关闭键盘,这样就不会遮挡上一个活动中的共享元素

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

我也有同样的问题,对我来说,这是由recyclerview在第一次退出转换之后/期间执行更新引起的。我认为共享元素视图有时会被回收,这意味着它将不再可用于过渡动画,因此会发生崩溃(通常在返回过渡时,但有时在退出过渡时)。我通过在活动暂停时阻止更新(使用isRunning标志)解决了这个问题——注意,它正在暂停,但没有停止,因为它在后台仍然可见。此外,如果转换正在运行,我会阻止更新过程。我发现听这个回调就足够了:

Transition sharedElementExitTransition = getWindow().getSharedElementExitTransition();
        if (sharedElementExitTransition != null) {
            sharedElementExitTransition.addListener(.....);
        }
作为最后一项措施,虽然我不确定这是否会产生影响,但我也做了如上所述的
onTransitionStart
/
onTransitionEnd
/
中的
recyclerView.setLayoutFrozed(true)
/
回收视图.setLayoutFrozed(false)
,确保从
ViewHolder
中检索到
itemView

您可以通过以下方式按位置获取
ViewHolder

mRecyclerView.findViewHolderForAdapterPosition(position);

原因其实很简单: 当您导航回父活动或片段时,视图尚不存在(可能有多种原因)。
因此,您要做的是推迟回车转换,直到视图可用。

我的解决方法是在我的片段中调用onCreate()中的以下函数(但也适用于活动):


我也遇到过同样的问题,实际上我使用了firebase,我有一个信息列表,当用户点击它时,它将调用detailActivity with SharedInformation,在这个活动中,我使用firebase更新它,所以firebase事件更新列表项,如图所示,在这种情况下,调用此问题是因为回收者查看屏幕布局受到影响

它调用了一个异常,因为我们传递的转换id已经不存在了,所以我用这个方法解决了这个问题

onPause()我已冻结布局,onResume()将其设置为false


它正在工作。

遇到了同样的问题,这是由回收器视图在后台更新引起的,回收器视图将在notifyItemChanged(int index)时重新创建视图,因此共享视图被回收,返回时崩溃


我的解决方案是call
recyclerView.setItemAnimator(null),它将阻止“回收者视图”重新创建视图。

您是否可以添加所有相关代码,以便更轻松地
mRecyclerView.findViewHolderForAdapterPosition(position);
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;
        }
    });
}
 @Override
public void onPause() {
    super.onPause();
    mRecycler.setLayoutFrozen(true);
}

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