Как я могу предотвратить отображение строки состояния и панели навигации во время перехода анимации сцены активности?

Во-первых, мой статус-бэнд установлен на темно-коричневый, а мой фон на панели навигации по умолчанию черный. Я использую тему Material light.

Я начинаю новое действие с помощью ActivityOptions.makeSceneTransitionAnimation с переходом по умолчанию, и я замечаю, что и статусные, и навигационные полосы кратковременно исчезают до белого, а затем возвращаются к правильным цветам.

В соответствии с документацией:

Чтобы получить полный эффект перехода, вы должны включить переходы содержимого окна как для вызывающего, так и для вызываемого. В противном случае вызывающая активность начнет переход с выхода, но тогда вы увидите переход на окно (например, масштабирование или исчезновение)

Я использую getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); как для вызывающего, так и для вызываемого.

Аналогично, если я изменил переход ввода на слайд, на панели состояния и навигации на короткое время будет переход слайдов на белом фоне.

Как предотвратить отображение строки состояния и навигационной панели во время перехода анимации сцены активности?

Ответ 1

Есть два подхода, которые вы можете использовать, о которых я знаю, для предотвращения анимации навигации/строки состояния во время перехода:

Подход №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, который почти работал у меня... хотя мне все еще нужно было сделать пару модификаций.

В моей деятельности по вызову я использовал следующий код для запуска 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(), чтобы предотвратить "мигание" строки состояния и навигационной панели во время перехода:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_next);

    // Postpone the transition until the window 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+.

Ответ 2

Вам нужно поделиться ими в ActivityOptions.makeSceneTransitionAnimation.

например:

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

(извините psuedo, у меня нет точного значения android.R.id)

Вы можете выполнить соответствующий переход, разделив представления.

Ответ 3

Полностью запретить переходы Activity переходить на общие переходы элементов:

В завершающей операции вызовите getWindow(). setExitTransition (null);

В процессе ввода вызовите getWindow(). setEnterTransition (null);

Из fooobar.com/questions/57417/...

Я подозреваю, что это может иметь побочные эффекты, но не знаю точно. Это мертво просто и работает, хотя.

Предотвращение мигания определенных элементов:

Я начал с ответа Алекс Локвуд и сделал несколько экспериментов, чтобы попытаться заставить его работать. Ядро его правильно, хотя мне не нужен код, который он предлагает для принимающей операции, но я столкнулся с некоторыми проблемами, вызвав его в фрагменте (вместо Activity) и установив панель инструментов в качестве панели действий.

О, Фрагмент? Я видел много комментариев, что попытка получить ссылки на строку состояния и панель навигации была нулевой. То же самое произошло со мной, пока я не понял, что не найду их в макете Фрагмента... они были выше этого уровня. Следовательно, код ниже, чтобы получить представление декора из 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_appbarlayout и R.id.appbarlayout. Эти идентификаторы являются произвольными, если они соответствуют тому, что использует ваш код. В моем 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

Насколько я понимаю, это вызвано перекрытием переходов. Чтобы преодолеть эту проблему, я использовал следующие значения в методах onCreate() для обоих видов деятельности:

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

Ответ 5

Вот как я это сделал. Я разделяю как Status Bar, так и Navigation 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);
}

Ответ 6

getWindow().setEnterTransition(null); на входе Ввод удалил белый оверлей для меня.