android 5上的共享元素活动转换
我想在从一个活动转到另一个活动时设置一个共享元素转换 第一个活动有一个包含项目的RecyclerView。单击某个项目时,该项目应设置为新活动的动画 所以我定了一个目标 android:transitionName=“item”显示在最终活动视图和回收器视图项目视图中 在进行下一个活动时,我也会使用以下代码: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
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)时重新创建视图,因此共享视图被回收,返回时崩溃
我的解决方案是callrecyclerView.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);
}