web-dev-qa-db-ja.com

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

まず、ステータスバーの背景が暗い茶色に設定され、ナビゲーションバーの背景がデフォルトの黒になります。マテリアルライトテーマを使用しています。

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

ドキュメント によると:

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

呼び出しアクティビティと呼び出しアクティビティの両方でgetWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);を使用しています。

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

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

123
rlay3

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

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

移行中にナビゲーション/ステータスバーがフェードインおよびフェードアウトする理由は、移行が開始されると、デフォルトですべての非共有ビュー(ナビゲーション/ステータスバーの背景を含む)が呼び出し/呼び出しアクティビティでそれぞれフェードアウト/インするためです。ただし、ウィンドウのデフォルトのexit/enter 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の答えから成り立っています。almostは私のために働きました...まだいくつかの修正が必要でしたが。

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

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()メソッドに次のコードを追加する必要もありました。

@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+の投稿 をご覧ください。

210
Alex Lockwood

アクティビティの移行が共有要素の移行を妨げるのを完全に防ぎます:

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

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

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

これには副作用があるのではないかと疑っていますが、確実にはわかりません。それは非常にシンプルで動作します。

特定の要素の点滅を防ぐ:

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

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

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

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です。これにより、移行時に青いフラッシュが発生し、非常にイライラします。しかし、そのようなアプリ全体に影響を与える変更を加えるのではなく、今のところ、最初の迅速で汚いオプションを使用します。

4
Chad Schultz

私が理解している限り、これはアクティビティ遷移の重複が原因です。この問題を克服するために、両方のアクティビティのonCreate()メソッドで次の値を使用しました。

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

ActivityOptions.makeSceneTransitionAnimation.で共有する必要があります

例えば:

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

(申し訳ありませんが、正確なAndroid.R.id値は手元にありません)

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

3
klmprt

私はちょうどこの同じ問題を抱えていましたが、答えはパズルの重要な部分を見逃しているようです。共有要素の遷移では、すべてがDestination Activityで発生することに注意してください。

点滅効果を削除するには、呼び出されるアクティビティに次を追加します。

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

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

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

2
LukeWaggoner

EnteringトランジションのgetWindow().setEnterTransition(null);は、白いオーバーレイを削除しました。

1
Dominic Davies

これが私がやった方法です。 SharedElementTransitionImageViewとともにStatus BarNavigation Barの両方を共有します:

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);
}
0
toobsco42