Etkinlik sahnesi animasyon geçişi sırasında durum çubuğunun ve gezinme çubuğunun hareket etmesini nasıl engelleyebilirim?


127

Öncelikle, durum çubuğu arka planım koyu kahverengiye ayarlandı ve gezinme çubuğu arka planım varsayılan siyah. Materyal ışık temasını kullanıyorum.

Kullanarak yeni bir aktiviteye başlıyorum ActivityOptions.makeSceneTransitionAnimationVarsayılan geçişleri başlatıyorum ve hem durum hem de gezinme çubuklarının kısa bir süre beyaza ve ardından doğru renklere döndüğünü fark ettim.

Belgelere göre :

Bir geçişin tam etkisini elde etmek için, hem arama hem de çağrılan etkinliklerde pencere içeriği geçişlerini etkinleştirmeniz gerekir. Aksi takdirde, arama etkinliği çıkış geçişini başlatır, ancak daha sonra bir pencere geçişi görürsünüz (ölçekleme veya solma gibi)

Ben kullanıyorum getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);arama ve denilen faaliyetlerin her ikisinde.

Benzer şekilde, bir slayta giriş geçişini değiştirirsem, hem durum hem de gezinme çubuklarında kısaca beyaz arka planlı bir slayt geçişi olur.

Etkinlik sahnesi animasyon geçişi sırasında durum çubuğunun ve gezinme çubuğunun hareket etmesini nasıl engelleyebilirim?

Yanıtlar:


217

Geçiş sırasında gezinme / durum çubuğunun hareket etmesini önlemek için kullanabileceğim iki yaklaşım var:

Yaklaşım 1: Durum çubuğunu ve gezinme çubuğunu pencerenin varsayılan çıkışından / solmaya geç geçişinden hariç tutun

Gezinme / durum çubuğunun geçiş sırasında yavaşlamasının ve kaybolmasının nedeni, varsayılan olarak tüm paylaşılmayan görünümlerin (gezinme / durum çubuğu arka planları dahil) geçiş başladıktan sonra sırasıyla aramanızda / çağrılan Aktivitelerde kaybolması / kapanmasıdır. . Bununla birlikte, gezinme / durum çubuğu arka planlarını pencerenin varsayılan çıkış / girme Fadegeçişinden hariç tutarak bunu kolayca aşabilirsiniz. Aşağıdaki kodu Aktivitelerinizin onCreate()yöntemlerine eklemeniz yeterlidir :

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

Bu geçiş ayrıca XML kullanılarak aktivitenin temasında da (yani kendi res/transition/window_fade.xmldosyanızda) bildirilebilir:

<?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>

Yaklaşım 2: Durum çubuğunu ve gezinme çubuğunu paylaşılan öğeler olarak ekleyin

Bu yaklaşım, klmprt'nin cevabından yola çıkarak, neredeyse benim için işe yaradı ... yine de birkaç değişiklik yapmam gerekiyordu.

Çağıran Aktivitemde, Aktiviteyi başlatmak için aşağıdaki kodu kullandım:

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

Şimdiye kadar bu, aslında klmprt'nin cevabında önerdiği şeyle aynı. Ancak, onCreate()geçiş sırasında durum çubuğunun ve gezinme çubuğunun "yanıp sönmesini" önlemek için Aktivite yöntemime şu kodu da eklemem gerekiyordu :

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

Durum çubuğunu ve gezinme çubuğu arka planlarını paylaşılan öğeler olarak eklemek, onları pencerenin varsayılan çıkış / giriş solma geçişinin üstüne çizilmeye zorlar, yani geçiş sırasında solmazlar. Bu yaklaşımla ilgili daha fazla tartışma bu Google+ yayınında bulunabilir .


14
FindViewById'nin (android.R.id.navigationBarBackground) Lollipop'ta neden boş döndürdüğüne dair herhangi bir fikriniz var mı? Appcompat-v7
radzio

3
Yaklaşım # 2 işe yarıyor, ancak geçiş gerçekleştiğinde hala bir titreme var (aktivitede). durum çubuğu ve gezinme çubuğu artık yanıp sönmüyor.
Akshat

16
@alex Bu, android.support.design.widget.TabLayout ve android.support.design.widget.AppBarLayout ile yeni destek kitaplığına geçene kadar benim için neredeyse mükemmel çalıştı - şimdi titreme geri geldi
Noa Drach

6
android.R.id.navigationBarBackground, ekranda gezinme çubuğu olmadığı için Samsung veya HTC cihazlarında size bir NPE verebilir. Bunları paylaşılan öğeler olarak eklemeden önce boş bir kontrol yapın
Boy

8
Bu çözümü nexus 6'da android nugat ile deniyorum. Ancak her iki yaklaşım da benim için işe yaramıyor.
Pardeep Kr

4

Etkinlik geçişlerinin paylaşılan öğe geçişlerine müdahale etmesini tamamen önleyin:

Çıkış etkinliğinde getWindow (). SetExitTransition (null);

Giriş etkinliğinde getWindow (). SetEnterTransition (null);

Gönderen https://stackoverflow.com/a/34907685/967131

Bunun yan etkileri olabileceğinden şüpheleniyorum, ancak kesin olarak bilmiyorum. Çok basit ve yine de çalışıyor.

Belirli öğelerin yanıp sönmesini önleyin:

Alex Lockwood'un cevabıyla başladım ve işe yaramaya çalışmak için biraz deney yaptım. Özü doğrudur, ancak alıcı Aktivite için önerdiği koda ihtiyacım olmasa da, onu bir Fragment (Aktivite yerine) olarak adlandırarak ve eylem çubuğu olarak bir araç çubuğu ayarlayarak bazı problemlerle karşılaştım.

Oh, Fragment olayı mı? Durum çubuğuna ve gezinme çubuğuna referanslar almaya çalışırken boş olan birçok yorum gördüm. Aynı şey bana da oldu, onları Fragment'in düzeninde bulamayacağımı anlayana kadar ... onlar bu seviyenin üstündeydiler. Bu nedenle, Aktiviteden dekor görünümünü almak ve bunu aramak için aşağıdaki kodu kullanın. Sonra onları sorunsuz buldum.

Sonunda, şu yardımcı yöntemi geliştirdim:

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

Not R.string.transition_appbarlayout ve R.id.appbarlayout . Bu kimlikler, kodunuzun kullandığı ile eşleştikleri sürece keyfidir. XML'imde, özel eylem çubuğunu şu şekilde düzenliyorum (esaslara göre düzenlenmiş):

<?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>

Bunun gibi bir Araç Çubuğu kullanmazsanız, bu parça yardımcı program yönteminden kaldırılabilir.

Sonra Fragmanınızda şöyle çağırırsınız:

startActivity(intent, UIUtils.transitionOptions(getActivity(),
                        R.id.**my_view**,
                        R.string.**transition_my_view**));

XML'nizle eşleştiği sürece istediğiniz değerleri kullanın.

Bu, geçiş sırasında durum çubuğunun, araç çubuğunun ve gezinme çubuğunun (geri / ana sayfa / son uygulamalar düğmeleri) yanıp sönmesini engeller. Aktivite geçişinin geri kalanı normaldir.

Benim durumumda, uygulama temamız android:windowBackgroundmavi. Bu, geçişte oldukça sinir bozucu olan mavi bir flaşa neden olur. Ancak, tüm uygulamayı bu şekilde etkileyen bir değişiklik yapmak yerine, şimdilik ilk, hızlı ve kirli seçeneği kullanıyorum.


3

Onları paylaşmalısın ActivityOptions.makeSceneTransitionAnimation.

Örneğin:

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

(psuedo için özür dilerim; elimde tam android.R.id değeri yok)

Görünümleri paylaştıktan sonra uygun bir geçiş çalıştırabilirsiniz.


Bu senin için çalıştı mı? Bunu denedim ve durum çubuğu ve gezinme çubuğu geçiş sırasında hala beyaz renkte yanıp sönüyor.
rlay3

Evet, benim için çalıştı. Geçici olarak onlarla çakışabilecek başka bir görüş olmadığından emin misiniz? Sorunu izole etmek için 'korumalı' bir ortamda basit bir etkinlik geçişi kurmayı denediniz mi?
klmprt

@klmprt Çalışması için giriş geçişini de ertelemeniz gerektiğini düşünüyorum ... Ayrıca durum / gezinme çubuklarının sadece görünümleri paylaşarak hareket etmesini engelleyemedim. Sanırım, giriş geçişinin başlamasına izin vermeden önce pencerenin dekor görünümünün düzenini bitirmesini beklemeniz gerekiyor.
Alex Lockwood

@klmprt Cevabımın hala ele almadığı şey, geçiş sırasında Eylem Çubuğunun arka plan renginin animasyonunun nasıl önleneceği. Her iki Aktivite de aynı Eylem Çubuğu arka plan rengini paylaşıyorsa, eylem çubuğunun arka plan rengi, çağıran Aktivitenin eylem çubuğu yavaş yavaş kaybolduğunda ve çağrılan Aktivitenin eylem çubuğu yavaşça belirdiğinde canlandırılır. Bunu nasıl aşacağınız konusunda herhangi bir fikriniz var mı? konu?
Alex Lockwood

@klmprt Aslında daha da iyi bir çözüm olduğunu düşünüyorum. Gezinme / durum çubuğu arka planlarını pencerenin varsayılan çıkış / solmaya gir geçişinde hedefler olarak hariç tutabilirsiniz. Ayrıntılar için güncellenmiş cevabıma bakın.
Alex Lockwood

3

Anladığım kadarıyla bu, etkinlik geçişinin çakışmasından kaynaklanıyor. Bu sorunun üstesinden gelmek için onCreate()her iki etkinliğin yöntemlerinde aşağıdaki değerleri kullandım :

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

3

Ben de aynı sorunu yaşadım ve cevaplarda bulmacanın kritik bir parçası eksik görünüyor. Paylaşılan bir öğe geçişinde her şeyin Hedef Etkinliğinde gerçekleştiğini unutmayın .

Yanıp sönme efektini kaldırmak için, çağrılan aktiviteye aşağıdakileri eklemeniz yeterlidir:

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

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

Bu probleminizi çözmeli!


Selam. Bu, en üst yanıttaki Yaklaşım 1 ile aynı değil mi?
rlay3

@ rlay3 Tamamen değil. Anladığım kadarıyla, bunun yalnızca hedef etkinliğinde ayarlanması gerektiğinden asla bahsetmiyor.
LukeWaggoner

hey @LukeWaggoner bana bu konuda yardım edebilir misin: stackoverflow.com/questions/50189286/…
blackHawk

Durum çubuğunu ve gezinme çubuğunu hem etkinlikte, hem arayan hem de aranan kişide hariç tutmalısınız.
Giovanni Di Gregorio

1

getWindow().setEnterTransition(null); Giriş geçişinde benim için beyaz bindirmeyi kaldırdı.


0

İşte böyle yaptım. Her iki paylaşan Status Barve Navigation Barde SharedElementTransitionbir birlikte 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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.