Parça kullanırken Android Gezinme Çekmecesi görüntüsü ve Yukarı düzeltme işareti arasında geçiş yapma


177

Gezinme Çekmecesini kullanırken Android geliştiricileri, ActionBar'da "yalnızca Gezinme Çekmecesinde temsil edilen ekranların gerçekte Gezinme Çekmecesi görüntüsüne sahip olmasını" ve "diğer tüm ekranların geleneksel yukarı karatın olmasını" önerir.

Ayrıntılar için buraya bakın: http://youtu.be/F5COhlbpIbY

Birden fazla düzeydeki parçayı kontrol etmek için tek bir etkinlik kullanıyorum ve Gezinme Çekmecesi görüntüsünü her seviyede görüntüleyebilir ve çalıştırabilirim.

Daha düşük seviye parçaları oluştururken ActionBarDrawerToggle setDrawerIndicatorEnabled(false)Gezinme Çekmecesi görüntüsünü gizlemek ve Yukarı işaretini görüntülemek için

LowerLevelFragment lowFrag = new LowerLevelFragment();

//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout, 
lowFrag, "lowerFrag").addToBackStack(null).commit();

Yaşadığım sorun, en üst düzey parçalara geri döndüğümde, yukarı gezinti orijinal Gezinti Çekmecesi görüntüsü yerine hala gösteriliyor. Gezinme Çekmecesi görüntüsünü yeniden görüntülemek için üst düzey parçalarda ActionBar'ın nasıl "yenileneceği" konusunda herhangi bir öneriniz var mı?


Çözüm

Tom'un önerisi benim için çalıştı. İşte yaptım:

Ana aktivite

Bu etkinlik uygulamadaki tüm parçaları kontrol eder.

Başkalarını değiştirmek için yeni parçalar hazırlarken, DrawerToggle'ı şu şekilde ayarladım setDrawerIndicatorEnabled(false):

LowerLevelFragment lowFrag = new LowerLevelFragment();

//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout,   
lowFrag).addToBackStack(null).commit();

Sonra, geçersiz onBackPressedkılmada, DrawerToggle'ı şu şekilde ayarlayarak yukarıdakileri geri aldım setDrawerIndicatorEnabled(true):

@Override
public void onBackPressed() {
    super.onBackPressed();
    // turn on the Navigation Drawer image; 
    // this is called in the LowerLevelFragments
    setDrawerIndicatorEnabled(true)
}

LowerLevelFragments'ta

Değiştirdiğim onCreateve onOptionsItemSelectedbeğendiğim parçalarda :

In onCreateeklenen setHasOptionsMenu(true)seçenekler menüsünü yapılandırarak etkinleştirmek için. Ayrıca set setDisplayHomeAsUpEnabled(true)etkinleştirmek için < İşlem Çubuğu içinde:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // needed to indicate that the fragment would 
    // like to add items to the Options Menu        
    setHasOptionsMenu(true);    
    // update the actionbar to show the up carat/affordance 
    getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}

Ardından < tuşuna onOptionsItemSelectedher basıldığında , hiyerarşide bir düzey yukarı çıkmak ve Gezinme Çekmecesi Görüntüsünü görüntülemek için etkinlikten çağrılır:onBackPressed()

@Override
public boolean onOptionsItemSelected(MenuItem item) {   
    // Get item selected and deal with it
    switch (item.getItemId()) {
        case android.R.id.home:
            //called when the up affordance/carat in actionbar is pressed
            getActivity().onBackPressed();
            return true;
         
    }

2
Ayrıca onBackPressed () yönteminizde, getFragmentManager (). GetBackStackEntryCount () yöntemiyle arka yığınta kaç giriş olduğunu kontrol edebilir ve yalnızca sonuç 0 ise çekmece göstergesini etkinleştirebilirsiniz.
pvshnik

2
Bu çok faydalı! Yayınınızın "çözüm" bölümünü taşımalı ve bunu gerçek bir "yanıt" yapmalısınız. Sen upvotes için daha fazla puan alırsınız ve onu olduğu sonuçta bir cevap
Oleksiy

Neden burada parçasını değiştiriyorsanız: .replace(R.id.frag_layout. Eğer bu bir başka hiyerarşi seviyesi ise sizden .addbackstack'e gitmenizi beklerdim.
JJD

5
Kardeşim, theDrawerToggle.setDrawerIndicatorEnabled(false);parçanın içine nasıl atıfta bulunuyorsun ? Ana Faaliyet sınıfı dosyasında bildirildiğini düşünüyorum. Bu referans için bir yol bulamıyorum. İpucu var mı?
Skynet

1
Bir araç çubuğu kullanırken, bu arada evi kullanmamak için ekran seçeneklerini değiştirmek zorunda kaldım. Aksi takdirde (dahili android.support.v7.internal.widget paketinin içindeki) setDisplayOptions()yöntem ToolbarWidgetWrapper, aynı parçayı ikinci kez girerken simgeyi yeniden oluşturmaz. Diğerleri de bu sorunla karşılaştıklarında bunu burada bırakıyorum.
Wolfram Rittmeyer

Yanıtlar:


29

Daha düşük seviyeli parçaları uygulamak için, daha düşük seviyeli parçayı yeni bir etkinliğe uygulamak yerine mevcut parçayı değiştirdiğinizi yazdınız.

Sonra geri işlevselliği elle uygulamak zorunda olacağını düşünürdüm: kullanıcı geri bastırdığınızda (örneğin Activity::onBackPressedgeçersiz kılma) yığını açılır kodu var . Yani, nerede yaparsanız yapın, tersine çevirebilirsiniz setDrawerIndicatorEnabled.


Teşekkürler Tom, işe yaradı! Orijinal yayını kullandığım çözümle güncelledim.
EvilAsh

6
DrawerToggle'a alt düzey bir parçada nasıl başvurulur? Ana faaliyette tanımlanmıştır, başımı bulamıyorum!
Skynet

1
Aktiviteyi parçadan alabilirsiniz. Bu nedenle, çekmece geçişine erişmek için ana etkinliğinize bir alıcı ekleyin.
Raphael Royer-Rivard

83

1-2-3 kadar kolaydır.

Eğer başarmak istiyorsanız:

1) Çekmece Göstergesi - Arka Yığında hiçbir parça olmadığında veya Çekmece açıldığında

2) Ok - Bazı Parçalar Arka Yığındayken

private FragmentManager.OnBackStackChangedListener
        mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
    @Override
    public void onBackStackChanged() {
        syncActionBarArrowState();
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    getSupportActionBar().setDisplayShowHomeEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    mDrawerToggle = new ActionBarDrawerToggle(
            this,             
            mDrawerLayout,  
            R.drawable.ic_navigation_drawer, 
            0, 
            0  
    ) {

        public void onDrawerClosed(View view) {
            syncActionBarArrowState();
        }

        public void onDrawerOpened(View drawerView) {
            mDrawerToggle.setDrawerIndicatorEnabled(true);
        }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
    getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener);
}

@Override
protected void onDestroy() {
    getSupportFragmentManager().removeOnBackStackChangedListener(mOnBackStackChangedListener);
    super.onDestroy();
}

private void syncActionBarArrowState() {
    int backStackEntryCount = 
        getSupportFragmentManager().getBackStackEntryCount();
    mDrawerToggle.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}

3) Her iki gösterge şekline göre hareket edecek

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (mDrawerToggle.isDrawerIndicatorEnabled() && 
        mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    } else if (item.getItemId() == android.R.id.home && 
               getSupportFragmentManager().popBackStackImmediate()) {
        return true;
    } else {
        return super.onOptionsItemSelected(item);
    }
}

PS 3 satırlı gösterge davranışı hakkında diğer ipuçları için Android Geliştiricileri'nde Gezinme Çekmecesi Oluşturma konusuna bakın .


3
Seninkine benzer bir şey buldum. Bence bu çözüm (gösterilenler arasında geçiş yapmak için BackStackChangedListener kullanarak) en zarif. Ancak iki değişiklik var: 1) onDrawerClosed / onDrawerOpened çağrılarında çekmece göstergesini çağırmıyorum / değiştirmiyorum - gerekmiyor ve 2) Parçaların kendilerinin bir miras bırakan bir AbstractFragment yaparak yukarı gezinme işlemine izin verdim. her zaman setHasOptionsMenu (true) öğesini çağıranOptionsItemSelected (..) öğesini uygular;
Espen Riskedal

2
Ayrıca gezinti çekmecesi için kaydırma hareketini ok modunda kilitlemelisiniz: mDrawerLayout.setDrawerLockMode (DrawerLayout.LOCK_MODE_LOCKED_CLOSED); ve çekmece gösterge modunda tekrar etkinleştirin
artkoenig

5
Tüm bunları NavigationDrawer fragmanımda yaptım. Bir çekicilik btw gibi çalışır, teşekkürler.
frostymarvelous

1
setActionBarArrowDependingOnFragmentsBackStack()... ne kadar uzun bir isim: P
S.Thiongane

2
A parçasından B parçasına gittiğimde ve A'yı backstack'e eklediğimde bu benim için yukarı düğmesini göstermiyor. :(
aandis

14

Bir sonraki şeyi kullandım:

getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
            @Override
            public void onBackStackChanged() {
                if(getSupportFragmentManager().getBackStackEntryCount() > 0){
                    mDrawerToggle.setDrawerIndicatorEnabled(false);
                    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                }
                else {
                    getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                    mDrawerToggle.setDrawerIndicatorEnabled(true);
                }
            }
        });

1
ÇOK TEŞEKKÜRLER Bu gerçekten işe yarayan tek kişi. Bunu eklediğimde, drawerToggle.setToolbarNavigationClickListener(bu dinleyici oku tıklarken çağrılır
EpicPandaForce

Teşekkürler @Yuriy, bu sorunumu çözmemde bana yardımcı oldu
Muhammad Shoaib Murtaza

12

Yukarı işlem çubuğu düğmeniz işe yaramazsa dinleyiciyi eklemeyi unutmayın:

// Navigation back icon listener
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onBackPressed();
        }
});

Ana ekran düğmeli bir çekmece navigasyonu uygulamakta sorun yaşıyorum, eylem düğmesi dışında her şey çalıştı.


10

DrawerToggle öğesinin durumuna bağlı olarak MainActivity'de Giriş öğesi seçimini yapmayı deneyin. Bu şekilde her parçaya aynı kodu eklemek zorunda kalmazsınız.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Only handle with DrawerToggle if the drawer indicator is enabled.
    if (mDrawerToggle.isDrawerIndicatorEnabled() &&
            mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle action buttons
    switch (item.getItemId()) {
        // Handle home button in non-drawer mode
        case android.R.id.home:
            onBackPressed();
            return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}

+1 temiz çözüm. Cevabınızın tamamen kullanılabilir olması için backstack'e bir çek eklemeniz gerekir. Boş olduğunda, çekmece göstergesini otomatik olarak true değerine ayarlayın.
HpTerm

@HpTerm Ben onBackPressed()her ikisi için de aynı davranışı istedim çünkü backstack ele .
dzeikei

6

TAKİP ET

@Dzeikei tarafından verilen çözüm temizdir, ancak fragmanlar kullanıldığında, backstack boşken çekmece göstergesinin ayarını otomatik olarak işlemek için genişletilebilir.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Only handle with DrawerToggle if the drawer indicator is enabled.
    if (mDrawerToggle.isDrawerIndicatorEnabled() &&
            mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle action buttons
    switch (item.getItemId()) {
        // Handle home button in non-drawer mode
        case android.R.id.home:
            // Use getSupportFragmentManager() to support older devices
            FragmentManager fragmentManager = getFragmentManager();
            fragmentManager.popBackStack();
            // Make sure transactions are finished before reading backstack count
            fragmentManager.executePendingTransactions();
            if (fragmentManager.getBackStackEntryCount() < 1){
                mDrawerToggle.setDrawerIndicatorEnabled(true);  
            }
            return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}

DÜZENLE

@JJD sorusu için.

Parçalar bir aktivitede tutulur / yönetilir. Yukarıdaki kod bu aktivitede bir kez yazılır, ancak yalnızca onOptionsItemSelected.

Uygulamalarımdan birinde, geri düğmesine basıldığında yukarı işaretin davranışını ele almam gerekiyordu. Bu geçersiz kılma ile halledilebilir onBackPressed.

@Override
public void onBackPressed() {
    // Use getSupportFragmentManager() to support older devices
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.executePendingTransactions();
    if (fragmentManager.getBackStackEntryCount() < 1){
        super.onBackPressed();
    } else {
        fragmentManager.executePendingTransactions();
        fragmentManager.popBackStack();
        fragmentManager.executePendingTransactions();
        if (fragmentManager.getBackStackEntryCount() < 1){
            mDrawerToggle.setDrawerIndicatorEnabled(true);
        }
    }
};

Arasında kod çoğaltma Not onOptionsItemSelectedve onBackPressedhangi bir yöntem oluşturma ve her iki yerde de bu yöntemi çağırarak önlenebilir.

Ayrıca executePendingTransactions, benim durumumun gerekli olduğu iki kez daha eklediğimi ya da bazen yukarı caret'in garip davranışlarına sahip olduğumu unutmayın.


Bu, Yukarı Düzeltme davranışını uygulamak için eklemem gereken tam kod mu yoksa diğer gönderilerden birine mi atıfta bulunuyorsunuz? Lütfen bunu netleştirin.
JJD

Düzenleme için teşekkürler. Aslında mDrawerTogglebir NavigationDrawerFragmentsınıf içinde kalıyorum . O eve düğmesi / göstergesi durumuna geçiş de gerek çalışma almak için - bkz: NavigationDrawerFragment#toggleDrawerIndicator. Ayrıca, ilk check-in ihtiyacınız olduğundan emin değilim onOptionsItemSelected: Ben uncommented. - Basitleştirilmiş örnek
JJD

Gözden geçirilmiş uygulama : İlk check-in konusunda haklısınız onOptionsItemSelected. Bu Gezinti Çekmecesinin hala üst düzey hiyerarşide açılmasını sağlar. Ancak, kodu içine taşındı NavigationDrawerFragment#onOptionsItemSelected. Bu bana maruz kalmama mDrawerToggleyardım ediyor MainActivity.
JJD

@JJD Hiyerarşinin her seviyesi için her şey yukarı düzeltme işi için biraz uğraştığımı hatırladım. Sizin için de çalıştığı sürece sorun değil. Tabii ki, dediğin gibi, kodu açığa çıkarmamak için başka bir yere taşıyabilirsin.
HpTerm

2

Hamburger menüsünün görünüm durumunu güncellemek için barındırma etkinliği için bir arayüz oluşturdum. Üst düzey fragmanlar için geçişi ayarlıyorum trueve yukarı <oku görüntülemek istediğim fragmanlar için geçişi ayarlıyorum false.

public class SomeFragment extends Fragment {

    public interface OnFragmentInteractionListener {
        public void showDrawerToggle(boolean showDrawerToggle);
    }

    private OnFragmentInteractionListener mListener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            this.mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        mListener.showDrawerToggle(false);
    }
}

O zaman Faaliyetimde ...

public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {

    private ActionBarDrawerToggle mDrawerToggle;

    public void showDrawerToggle(boolean showDrawerIndicator) {
        mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator);
    }

}

2

Bu cevap işe yaradı ama bununla ilgili küçük bir sorun vardı. getSupportActionBar().setDisplayHomeAsUpEnabled(false)Açıkça çağrılmadı ve backstack hiçbir öğe değişen böylece bile vardı çekmece simgesi gizlenmesine neden olan setActionBarArrowDependingOnFragmentsBackStack()yöntem benim için çalıştı.

private void setActionBarArrowDependingOnFragmentsBackStack() {
        int backStackEntryCount = getSupportFragmentManager()
                .getBackStackEntryCount();
        // If there are no items in the back stack
        if (backStackEntryCount == 0) {
            // Please make sure that UP CARAT is Hidden otherwise Drawer icon
            // wont display
            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
            // Display the Drawer Icon
            mDrawerToggle.setDrawerIndicatorEnabled(true);
        } else {
            // Show the Up carat
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            // Hide the Drawer Icon
            mDrawerToggle.setDrawerIndicatorEnabled(false);
        }

    }

benim durumumda rigth çözümü sadece actionBarDrawerToggle.setDrawerIndicatorEnabled (getSupportFragmentManager (). getBackStackEntryCount () <0) kullanıyordu;
Gorets

1

Mantık açıktır. Parça arka yığını açıksa geri göster düğmesi. Parça yığını net değilse malzeme hamburger arkası animasyonunu göster.

getSupportFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            syncActionBarArrowState();
        }
    }
);


private void syncActionBarArrowState() {
    int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
    mNavigationDrawerFragment.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}

//add these in Your NavigationDrawer fragment class

public void setDrawerIndicatorEnabled(boolean flag){
    ActionBar actionBar = getActionBar();
    if (!flag) {
        mDrawerToggle.setDrawerIndicatorEnabled(false);
        actionBar.setDisplayHomeAsUpEnabled(true);
        mDrawerToggle.setHomeAsUpIndicator(getColoredArrow());
    } else {
        mDrawerToggle.setDrawerIndicatorEnabled(true);
    }
    mDrawerToggle.syncState();
    getActivity().supportInvalidateOptionsMenu();
}

//download back button from this(https://www.google.com/design/icons/) website and add to your project

private Drawable getColoredArrow() {
    Drawable arrowDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_arrow_back_black_24dp);
    Drawable wrapped = DrawableCompat.wrap(arrowDrawable);

    if (arrowDrawable != null && wrapped != null) {
        // This should avoid tinting all the arrows
        arrowDrawable.mutate();
        DrawableCompat.setTint(wrapped, Color.GRAY);
    }
    return wrapped;
}

1

GMAIL uygulamasına bir göz atıp carret / affordance simgesini aramak için buraya gelirseniz ..

Sizden bunu yapmanızı rica ediyorum, yukarıdaki cevabın hiçbiri net değildi. kabul edilen cevabı değiştirebildim.

  • NavigationDrawer -> Listview alt parçaları içerir.


  • alt parçalar şöyle listelenir

  • firstFragment == 0 konumu ---> bunun alt parçaları olacaktır -> parça

  • secondFragment
  • üçüncüFragman vb.

FirstFragment'ta başka bir parçanız var.

Bunu DrawerActivity'de ara

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getFragmentManager().getBackStackEntryCount() > 0) {
                mDrawerToggle.setDrawerIndicatorEnabled(false);
            } else {
                mDrawerToggle.setDrawerIndicatorEnabled(true);
            }
        }
    });

ve parçalanmış

    setHasOptionsMenu(true);    

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Get item selected and deal with it
    switch (item.getItemId()) {
        case android.R.id.home:
            //called when the up affordance/carat in actionbar is pressed
            activity.onBackPressed();
            return true;
    }
    return false;
}

OnBackPressed Çekmece etkinliği yönteminde, gezinme listesi simgesini yeniden etkinleştirmek için çekmece geçişini true olarak ayarlayın.

Teşekkürler, Pusp



0

IMO, riwnodennyk veya Tom'un çözümünde onNavigateUp () ( burada gösterildiği gibi) kullanarak daha temiz ve daha iyi çalışıyor gibi görünüyor. Sadece onOptionsItemSelected kodunu bununla değiştirin:

@Override
public boolean onSupportNavigateUp() {
    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        // handle up navigation
        return true;
    } else {
        return super.onSupportNavigateUp();
    }
}
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.