アクティビティシーンのアニメーションの遷移中にステータスバーとナビゲーションバーがアニメーション化しないようにするにはどうすればよいですか?


127

まず、ステータスバーの背景はダークブラウンに設定され、ナビゲーションバーの背景はデフォルトで黒になっています。マテリアルライトテーマを使用しています。

ActivityOptions.makeSceneTransitionAnimationデフォルトのトランジションを使用して新しいアクティビティを開始しています。ステータスバーとナビゲーションバーの両方が一時的に白にフェードし、その後正しい色に戻ります。

ドキュメントによると:

遷移の完全な効果を得るには、呼び出し側と呼び出し先の両方のアクティビティでウィンドウコンテンツの遷移を有効にする必要があります。それ以外の場合、呼び出しアクティビティは終了遷移を開始しますが、ウィンドウの遷移(スケールやフェードなど)が表示されます

私はgetWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);召しと召しの両方の活動に使用しています。

同様に、Enterトランジションをスライドに変更すると、ステータスバーとナビゲーションバーの両方に、短い背景のスライドトランジションが一時的に表示されます。

アクティビティシーンのアニメーションの遷移中にステータスバーとナビゲーションバーがアニメーション化しないようにするにはどうすればよいですか?

回答:


217

移行中にナビゲーション/ステータスバーがアニメーション化しないようにするために使用できる2つの方法があります。

アプローチ1:ステータスバーとナビゲーションバーをウィンドウのデフォルトの終了/フェードトランジションから除外する

移行中にナビゲーション/ステータスバーがフェードインおよびフェードアウトする理由は、デフォルトでは、すべての非共有ビュー(ナビゲーション/ステータスバーの背景を含む)は、トランジションが始まると、呼び出し/呼び出されたアクティビティでそれぞれフェードアウト/インになるためです。 。ただし、ウィンドウのデフォルトの終了/入力Fade遷移からナビゲーション/ステータスバーの背景を除外することで、これを簡単に回避できます。アクティビティの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:ステータスバーとナビゲーションバーを共有要素として追加する

このアプローチは、klmprtの答えに基づいいます。これは、ほとんど問題なく動作しました...まだいくつかの変更を加える必要がありました。

呼び出しアクティビティでは、次のコードを使用してアクティビティを開始しました。

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が彼の回答で提案したものと同じです。ただし、onCreate()遷移中にステータスバーとナビゲーションバーが「点滅」しないように、呼び出されたActivityのメソッドに次のコードを追加する必要もあります。

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

ステータスバーとナビゲーションバーの背景を共有要素として追加すると、ウィンドウのデフォルトのexit / enterフェード遷移の上に強制的に描画されます。つまり、遷移中にフェードしません。このアプローチの詳細については、このGoogle+の投稿をご覧ください。


14
findViewById(android.R.id.navigationBarBackground)がLollipopでnullを返す理由は何ですか?私はappcompat-v7を使用しています
radzio 2015

3
アプローチ#2は機能しますが、遷移が発生しても(アクティビティ内で)ちらつきが残ります。ステータスバーとナビゲーションバーはもうフリックしません。
Akshat

16
@alexこれは、android.support.design.widget.TabLayoutandroid.support.design.widget.AppBarLayoutを備えた新しいサポートライブラリに切り替えるまで、ほぼ完璧に機能しました-ちらつきが戻ってきました
Noa Drach

6
android.R.id.navigationBarBackgroundは、画面上のナビゲーションバーがないため、SamsungまたはHTCデバイスでNPEを提供できます。共有要素として追加する前にnullチェックを実行する
Boy

8
私はAndroid Nougatを搭載したNexus 6でこのソリューションを試しています。しかし、どちらのアプローチもうまくいきません。
Pardeep Kr 2016

4

アクティビティの遷移が共有要素の遷移を妨害しないようにします。

終了するアクティビティで、getWindow()。setExitTransition(null);を呼び出します。

Enteringアクティビティで、getWindow()。setEnterTransition(null);を呼び出します。

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

これには副作用があるのではないかと思いますが、確かではありません。それは非常にシンプルでありながら機能します。

特定の要素が点滅するのを防ぐ:

私はアレックスロックウッドの答えから始めて、それを機能させるためにかなりの実験を行いました。コアは正しいですが、受信側のアクティビティに対して彼が提案するコードは必要ありませんでしたが、(アクティビティではなく)フラグメントでそれを呼び出して、ツールバーをアクションバーとして設定することで、いくつかの問題に遭遇しました。

ああ、フラグメントの事?ステータスバーとナビゲーションバーへの参照を取得しようとすると無効になるというコメントがたくさんありました。同じことが私にも起こりました。フラグメントのレイアウトでそれらを見つけられないことに気づくまで、それらはそのレベルより上でした。したがって、以下のコードはアクティビティから装飾ビューを取得して検索します。その後、問題なく見つけました。

最後に、私はこのユーティリティメソッドを開発しました。

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と一致する限り、任意の値を使用します。

これにより、ステータスバー、ツールバー、およびナビゲーションバー(戻る/ホーム/最近のアプリボタン)が移行中に点滅するのを防ぎます。残りのアクティビティ遷移は正常です。

私の場合、アプリのテーマはandroid:windowBackground青色です。これにより、移行中に青いフラッシュが発生し、非常にイライラします。しかし、そのようなアプリ全体に影響を与える変更を行うのではなく、今のところ、最初の迅速でダーティなオプションを使用します。


3

あなたはそれらを共有する必要があります ActivityOptions.makeSceneTransitionAnimation.

例えば:

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

(疑似失礼、手元に正確なandroid.R.id値がありません)

ビューを共有した後、適切なトランジションを実行できます。


これでうまくいきましたか?これを試してみたところ、移行中にステータスバーとナビゲーションバーがまだ白く点滅しています。
rlay3 2014年

はい、うまくいきました。一時的に重なっている可能性のある別のビューがないと確信していますか?問題を分離するために、「サンドボックス」環境で単純なアクティビティ遷移を設定してみましたか?
klmprt 2014年

@klmprtそれを機能させるには、Enterトランジションも延期する必要があると思います...また、ビューを共有するだけでは、ステータス/ナビゲーションバーがアニメーション化するのを防ぐことができませんでした。入力遷移を開始する前に、ウィンドウの装飾ビューがそのレイアウトを完了するのを待つ必要があると思います。
Alex Lockwood 2014年

@klmprt私の回答ではまだ対処していませんが、遷移中にアクションバーの背景色がアニメーション化しないようにする方法です。両方のアクティビティが同じアクションバーの背景色を共有している場合、呼び出し元のアクティビティのアクションバーが徐々にフェードアウトし、呼び出されたアクティビティのアクションバーがゆっくりとフェードインすると、アクションバーの背景色がアニメーション表示されます。これを回避する方法はありますか?問題?
Alex Lockwood 2014年

@klmprt実際、もっと良い解決策があると思います。ウィンドウのデフォルトのexit / enterフェード遷移のターゲットとして、ナビゲーション/ステータスバーの背景を単に除外できます。詳細については、更新された回答を参照してください。
Alex Lockwood 2014年

3

私が理解している限り、これはアクティビティ遷移のオーバーラップが原因です。この問題を克服するために、私はonCreate()両方の活動の方法で次の値を使用しました:

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

3

私はこれと同じ問題を抱えていましたが、答えはパズルの重要な部分を欠いているようです。共有要素の遷移では、すべてがDestinationアクティビティで発生することに注意してください。

点滅する効果を削除するには、呼び出されているアクティビティに以下を追加するだけです。

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

getWindow().setEnterTransition(fade);
getWindow().setExitTransition(fade);

これで問題が解決するはずです!


こんにちは。これは、トップアンサーのアプローチ#1と同じではありませんか?
rlay3 2018年

@ rlay3完全にではありません。私が知る限り、彼はこれが目的地の活動でのみ設定される必要があるという事実に決して言及しません。
LukeWaggoner

:@LukeWaggonerねえ、あなたは私にこの助けることができるstackoverflow.com/questions/50189286/...
ブラックホーク

呼び出し元と呼び出し先の両方のアクティビティでステータスバーとナビゲーションバーを除外する必要があります。
Giovanni Di Gregorio


0

これが私がやった方法です。私は両方の共有Status BarNavigation Bar中をSharedElementTransition一緒に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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.