在活动场景animation转换过程中,如何防止状态栏和导航栏animation?
首先,我的状态栏背景设置为深褐色,导航栏背景为默认黑色。 我正在使用“材质”灯光主题。
我使用ActivityOptions.makeSceneTransitionAnimation
以默认转换开始一个新的活动,我注意到状态和导航栏简短地淡化为白色,然后回到正确的颜色。
根据文件 :
要获得转换的全部效果,必须在调用和被调用的活动上启用窗口内容转换。 否则,调用活动将开始退出转换,但是您将看到一个窗口转换(如缩放或淡入淡出)
我正在使用getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
在呼叫和被叫的活动。
同样,如果我将input转换更改为幻灯片,则状态和导航栏都会短暂地以白色背景进行幻灯片切换。
在活动场景animation过渡期间,如何防止状态栏和导航栏animation?
有两种方法可以用来防止导航/状态栏在转换过程中出现animation:
方法#1:从窗口的默认退出/input淡入转换中排除状态栏和导航栏
在转换过程中导航/状态栏淡入和淡出的原因是,默认情况下,一旦转换开始,所有非共享视图(包括导航/状态栏背景)将分别在您的调用/被调用的Activity中淡出/ 。 但是,通过从窗口的默认退出/inputFade
转换中排除导航/状态栏背景,您可以轻松地解决此问题。 只需将以下代码添加到您的Activity的onCreate()
方法中即可:
Transition fade = new Fade(); fade.excludeTarget(android.R.id.statusBarBackground, true); fade.excludeTarget(android.R.id.navigationBarBackground, true); getWindow().setExitTransition(fade); getWindow().setEnterTransition(fade);
这个转换也可以在使用XML的活动主题中声明(即在你自己的res/transition/window_fade.xml
文件中):
<?xml version="1.0" encoding="utf-8"?> <fade xmlns:android="http://schemas.android.com/apk/res/android"> <targets> <target android:excludeId="@android:id/statusBarBackground"/> <target android:excludeId="@android:id/navigationBarBackground"/> </targets> </fade>
方法2:将状态栏和导航栏添加为共享元素
这种方法build立在klmprt的答案基础上, 几乎为我工作…虽然我仍然需要做一些修改。
在我的调用活动中,我使用下面的代码来启动活动:
View statusBar = findViewById(android.R.id.statusBarBackground); View navigationBar = findViewById(android.R.id.navigationBarBackground); List<Pair<View, String>> pairs = new ArrayList<>(); pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME)); pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME)); pairs.add(Pair.create(mSharedElement, mSharedElement.getTransitionName())); Bundle options = ActivityOptions.makeSceneTransitionAnimation(activity, pairs.toArray(new Pair[pairs.size()])).toBundle(); startActivity(new Intent(context, NextActivity.class), options);
到目前为止,这与klmprt在答案中提出的基本相同。 不过,我还需要在我的Activity的onCreate()
方法中添加下面的代码,以防止状态栏和导航栏在转换过程中“闪烁”:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_next); // Postpone the transition until the window's decor view has // finished its layout. postponeEnterTransition(); final View decor = getWindow().getDecorView(); decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { decor.getViewTreeObserver().removeOnPreDrawListener(this); startPostponedEnterTransition(); return true; } }); }
将状态栏和导航栏背景添加为共享元素将强制将其绘制在窗口的默认退出/淡入淡出转换之上,这意味着在转换期间它们不会褪色。 关于这种方法的更多讨论可以在这篇Google+信息中find。
您需要在ActivityOptions.makeSceneTransitionAnimation.
共享它们ActivityOptions.makeSceneTransitionAnimation.
例如:
ActivityOptions.makeSceneTransitionAnimation(... Pair.create(activity.findViewById(android.R.id.window_status_bar), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME)
(对不起,我没有确切的android.R.id值)
共享视图后,您可以运行适当的转换。
完全防止活动转换干扰共享元素转换:
在退出的活动中,调用getWindow()。setExitTransition(null);
在进入的活动中,调用getWindow()。setEnterTransition(null);
从https://stackoverflow.com/a/34907685/967131
我怀疑这可能有副作用,但不知道肯定。 这是死了简单,工程虽然。
防止特定元素闪烁:
我从Alex Lockwood的回答开始,进行了一些尝试,试图使其工作。 它的核心是正确的,虽然我不需要代码,他build议接收活动,但我遇到了一些问题,通过调用它在一个片段(而不是一个活动),并通过设置一个工具栏作为操作栏。
哦,碎片的事情? 我看到很多评论,试图检索对状态栏和导航栏的引用是空的。 同样的事情也发生在我身上,直到我意识到我不会在碎片的布局中find那些…他们高于这个水平。 因此,下面的代码从活动中获取装饰视图并进行search。 然后我发现他们没有问题。
最后,我开发了这个实用方法:
public static Bundle transitionOptions(Activity activity, int transitionViewResId, int transitionNameResId) { if (VERSION.SDK_INT < VERSION_CODES.LOLLIPOP) { return null; } View decorView = activity.getWindow().getDecorView(); View statusBar = decorView.findViewById(android.R.id.statusBarBackground); View navigationBar = decorView.findViewById(android.R.id.navigationBarBackground); View appBarLayout = decorView.findViewById(**R.id.appbarlayout**); View transitionView = decorView.findViewById(transitionViewResId); String transitionName = activity.getString(transitionNameResId); List<Pair<View, String>> pairs = new ArrayList<>(); pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME)); pairs.add(Pair.create(navigationBar, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME)); if (appBarLayout != null) { pairs.add(Pair.create(appBarLayout, activity.getString(**R.string.transition_appbarlayout**))); } pairs.add(Pair.create(transitionView, transitionName)); //noinspection unchecked - we're not worried about the "unchecked" conversion of List<Pair> to Pair[] here return ActivityOptionsCompat.makeSceneTransitionAnimation(activity, pairs.toArray(new Pair[pairs.size()])) .toBundle(); }
注意R.string.transition_appbarlayout和R.id.appbarlayout 。 这些ID是任意的,只要它们与您的代码使用相匹配即可。 在我的XML中,我像这样布置自定义操作栏(编辑到要点):
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.AppBarLayout android:id="**@+id/appbarlayout**" android:transitionName="**@string/transition_appbarlayout**"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar"/> </android.support.design.widget.AppBarLayout>
如果您不使用这样的工具栏,则可以从实用程序方法中删除该部分。
那么你可以这样称呼你的碎片:
startActivity(intent, UIUtils.transitionOptions(getActivity(), R.id.**my_view**, R.string.**transition_my_view**));
使用任何你想要的值,只要它符合你的XML。
这可以防止状态栏,工具栏和导航栏(后退/主页/最近的应用程序button)在转换过程中闪烁。 活动转换的其余部分是正常的。
在我的情况下,我们的应用程序主题有一个android:windowBackground
的蓝色。 这导致了转换中的蓝色闪光,这是相当令人沮丧的。 而不是像这样做一个影响整个应用程序的变化,现在我正在用第一个,快速和肮脏的选项。
据我所知,这是由活动转换重叠造成的。 为了解决这个问题,我在两个活动的onCreate()
方法中使用了下列值:
getWindow().setAllowEnterTransitionOverlap(false); getWindow().setAllowReturnTransitionOverlap(false);
这是我如何做到的。 我在SharedElementTransition
共享Status Bar
和Navigation Bar
以及一个ImageView
:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { View imageView = view.findViewById(R.id.iv); Resources resources = view.getResources(); imageView.setTransitionName(resources.getString(R.string.transition_image_thumbnail)); Pair<View, String> p1 = Pair.create(imageView, resources.getString(R.string.transition_image_thumbnail)); Window window = getActivity().getWindow(); View navigationBar = getActivity().findViewById(android.R.id.navigationBarBackground); View statusBar = getActivity().findViewById(android.R.id.statusBarBackground); Pair<View, String> p2 = Pair.create(statusBar, statusBar.getTransitionName()); Pair<View, String> p3 = Pair.create(navigationBar, navigationBar.getTransitionName()); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), p1, p2, p3); ActivityCompat.startActivity(getActivity(), intent, options.toBundle()); } else { startActivity(intent); }
getWindow().setEnterTransition(null);
在进入转换删除白色覆盖对我来说。