首页 文章

如何在活动场景动画过渡期间阻止状态栏和导航栏动画?

提问于
浏览
118

首先,我的状态栏背景设置为深棕色,导航栏背景为默认黑色 . 我正在使用Material light主题 .

我正在使用带有默认过渡的 ActivityOptions.makeSceneTransitionAnimation 开始一个新活动,我注意到状态和导航栏都会短暂淡化为白色然后再返回正确的颜色 .

根据documentation

要获得转换的完整效果,必须在调用和被调用的活动上启用窗口内容转换 . 否则,调用活动将开始退出转换,但随后您将看到窗口转换(如缩放或淡入淡出)

我在调用和被调用的活动上使用 getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); .

同样,如果我将输入转换更改为幻灯片,状态和导航栏会短暂地具有带白色背景的幻灯片转换 .

如何在活动场景动画过渡期间阻止状态栏和导航栏动画?

7 回答

  • 0

    getWindow().setEnterTransition(null); 在输入转换上为我删除了白色叠加层 .

  • 1

    我刚才遇到了同样的问题,答案似乎错过了这个难题的关键部分 . 请记住,在共享元素转换中,所有内容都发生在目标活动中 .

    要删除闪烁效果,只需将以下内容添加到被调用的活动中:

    Fade fade = new Fade();
    fade.excludeTarget(android.R.id.statusBarBackground, true);
    fade.excludeTarget(android.R.id.navigationBarBackground, true);
    
    getWindow().setEnterTransition(fade);
    getWindow().setExitTransition(fade);
    

    这应该可以解决你的问题!

  • 4

    我知道有两种方法可以防止导航/状态栏在转换过程中动画化:

    方法#1:从窗口的默认退出/输入淡入淡出过渡中排除状态栏和导航栏

    导航/状态栏在转换期间淡入淡出的原因是,默认情况下,一旦转换开始,所有非共享视图(包括导航/状态栏背景)将分别在您的调用/被调用的活动中淡出/淡出 . 但是,您可以通过从窗口的默认退出/输入 Fade 转换中排除导航/状态栏背景来轻松解决此问题 . 只需将以下代码添加到Activitys的 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的答案之上,这对我来说几乎是有用的......虽然我仍需要进行一些修改 .

    在我的调用Activity中,我使用以下代码启动Activity:

    View statusBar = findViewById(android.R.id.statusBarBackground);
    View navigationBar = findViewById(android.R.id.navigationBarBackground);
    
    List<Pair<View, String>> pairs = new ArrayList<>();
    if (statusBar != null) {
      pairs.add(Pair.create(statusBar, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME));
    }
    if (navigationBar != null) {
      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() 方法中添加以下代码,以防止在转换期间状态栏和导航栏从"blinking":

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

    将状态栏和导航栏背景添加为共享元素将强制它们在窗口的默认退出/输入淡入淡出过渡之上绘制,这意味着它们在过渡期间不会淡出 . 关于这种方法的更多讨论可以在this Google+ post找到 .

  • 202

    Completely prevent Activity transitions from interfering with shared element transitions:

    在退出活动上,调用getWindow() . setExitTransition(null);在输入活动上,调用getWindow() . setEnterTransition(null);

    https://stackoverflow.com/a/34907685/967131

    我怀疑这可能有副作用,但不确定 . 虽然很简单但很有效 .

    Prevent specific elements from blinking:

    我从Alex Lockwood's answer开始,做了一些尝试,试图让它运作起来 . 它的核心是正确的,虽然我不需要他为接收Activity建议的代码,但我通过在Fragment(而不是Activity)中调用它并将工具栏设置为操作栏来遇到一些问题 .

    哦,片段的东西?我看到很多评论试图检索状态栏和导航栏的引用是空的 . 同样的事情也发生在我身上,直到我意识到我不会在Fragment的布局中找到那些......他们超过了那个级别 . 因此,下面的代码从Activity获取装饰视图并搜索 . 然后我发现它们没问题 .

    最后,我开发了这个实用方法:

    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_appbarlayoutR.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匹配即可 .

    这可以防止状态栏,工具栏和导航栏(后退/主页/最近的应用程序按钮)在转换期间闪烁 . 活动过渡的其余部分是正常的 .

    就我而言,我们的应用主题有一个 android:windowBackground 蓝色 . 这会导致过渡时出现蓝色闪光,这非常令人沮丧 . 但是,而不是像这样做一个影响整个应用程序的更改,现在我将使用第一个,快速和脏的选项 .

  • 3

    你需要在 ActivityOptions.makeSceneTransitionAnimation. 分享它们

    例如:

    ActivityOptions.makeSceneTransitionAnimation(... Pair.create(activity.findViewById(android.R.id.window_status_bar), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME)
    

    (原谅psuedo;我手边没有确切的android.R.id值)

    您可以在共享视图后运行适当的转换 .

  • 2

    据我了解,这是由活动过渡重叠引起的 . 为了解决这个问题,我在两个活动的 onCreate() 方法中使用了以下值:

    getWindow().setAllowEnterTransitionOverlap(false);
    getWindow().setAllowReturnTransitionOverlap(false);
    
  • 1

    我就是这样做的 . 我在 SharedElementTransition 中共享 Status BarNavigation 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);
    }
    

相关问题