parçalı eylem çubuğu yukarı gezinme


88

A , B ve C diyen üç sekmeye sahip sekmeli bir Actionbar / viewpager düzenim var . Sekme olarak sekmesi (fragman), başka bir fragmanı, mesela fragmanı ekleme D . ile

 DFragment f= new DFragment();
 ft.add(android.R.id.content, f, "");
 ft.remove(CFragment.this);
 ft.addToBackStack(null);
 ft.commit();

DFragment'ın onResume'daki eylem çubuğunu eklemek için değiştiriyorum:

ActionBar ab = getActivity().getActionBar();
ab.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayShowHomeEnabled(true);

Şimdi DFragment'da, donanım (telefon) Geri düğmesine bastığımda, CFragment seçiliyken orijinal Sekmeli (ABC) düzenine dönüyorum. Bu işlevselliğe işlem çubuğu yukarı düğmesiyle nasıl ulaşabilirim?


Yanıtlar:


186

OnBackStackChangedListenerBu kodu, Parça Etkinliğinize uygulayın ve ekleyin.

@Override
public void onCreate(Bundle savedInstanceState) {
    //Listen for changes in the back stack
    getSupportFragmentManager().addOnBackStackChangedListener(this);
    //Handle when activity is recreated like on orientation Change
    shouldDisplayHomeUp();
}

@Override
public void onBackStackChanged() {
    shouldDisplayHomeUp();
}

public void shouldDisplayHomeUp(){
   //Enable Up button only  if there are entries in the back stack
   boolean canGoBack = getSupportFragmentManager().getBackStackEntryCount()>0;
   getSupportActionBar().setDisplayHomeAsUpEnabled(canGoBack);
}

@Override
public boolean onSupportNavigateUp() {
    //This method is called when the up button is pressed. Just the pop back stack.
    getSupportFragmentManager().popBackStack();
    return true;
}

21
Hakkında onSupportNavigateUp(), "Yöntem, üst sınıfından yöntemi geçersiz kılmaz".
Fred

10
Zaten bir onOptionsItemSelectedürününüz varsa android.R.id.home, eklemek yerine itemId'yi kontrol etmek de mümkündür onSupportNavigateUp.
domsom

1
API sürümü> = 14 ise, onSupportNavigateUp @Override public boolean onNavigateUp () yerine onNavigateUp kullanın {// Yukarı düğmesine basıldığında bu yöntem çağrılır. Sadece geri tepme yığını. getFragmentManager (). popBackStack (); doğruya dön; }
Tejasvi Hegde

1
? Öğesinde uygulama simgenizin yanında görüntülenen bir yukarı imleci olması gerekiyor ActionBarmu? Bu kodu uyguladığımda bir tane görmüyorum. Yalnızca simgeye tıklayabiliyorum, ancak hiçbir şey yapmıyor. Android 4.0+.
Azurespot

3
OnBackStackChanged () geçersiz kılmazsa, etkinliğinizin FragmentManager.OnBackStackChangedListener arabirimini uyguladığından emin olun.
CBA110

42

Anladım. barındırma etkinliğinde onOptionsItemSelected öğesini geçersiz kılın ve backstack'i açın, ör.

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home: {
            FragmentManager fm = getSupportFragmentManager();
            if (fm.getBackStackEntryCount() > 0) {
                fm.popBackStack();
                return true;
            }
            break;
        }
    }
    return super.onOptionsItemSelected(item);
}

Çağrı getActionBar().setDisplayHomeAsUpEnabled(boolean);ve getActionBar().setHomeButtonEnabled(boolean);içinde onBackStackChanged()aşağıda bir cevap açıklandığı gibi.


3
ayrıca getActivity () 'yi çağırmanız gerekir. getActionBar (). setDisplayHomeAsUpEnabled (false); arka yığını
açtığınızda

Bunu yapmanın doğru yolu bu değil. Yukarı düğmesini etkinleştirmeye devam ediyor.
Roger Garzon Nieto

1
Bu kodu switchdava ile birlikte ifadenin içine koymalısınız android.R.id.home.
Fred

18

Bir ebeveyn etkinliğiniz varsa ve bu yukarı düğmesinin bir geri düğmesi olarak çalışmasını istiyorsanız, şu kodu kullanabilirsiniz:

bunu ana aktivite sınıfınızdaki onCreate'e ekleyin

getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
            if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
                getSupportActionBar().setHomeButtonEnabled(true);
                getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            } else {
                getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                getSupportActionBar().setHomeButtonEnabled(false);
            }
        }

    });

ve sonra onOptionsItemSelected'ı şu şekilde ekleyin:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
     ....
 }

Bunu genellikle her zaman kullanıyorum ve oldukça yasal görünüyor


1
ActivityBaşladığı parçaya geri dönmesi umuduyla bu kodu tam olarak, bir tanesinde kullanmayı denedim . Geri düğmesi uygulamama gittiğimde uygulama simgemin yanında görünüyor Activity, ancak simgeye tıklıyorum ve hiçbir şey olmuyor (parçaya geri dönmeli). Herhangi bir fikrin neden? Teşekkürler.
Azurespot

1
@Daniel kodunuz yasal .. işe yarıyor. Sadece deneme yakalama seçeneği ile etrafını sarmak isteyebilirsiniz .. Öngörülemeyen istisnaları ve uygulamaların çökmesini önlemeyi biliyorsunuz
Zuko

1
@NoniA. Bu sadece önceki bir parçaya (örneğin, parça B -> parça A) geri gidecek, eğer 1 parçayı yeni bir etkinlikte şişiriyorsanız, bu önceki etkinliğe geri dönmeyecektir.
Daniel Jonker

11

geri düğmesi gibi yukarı düğmesiyle geri dönebilirsiniz;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            super.onBackPressed();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

8

Bu sorunun eski olduğunu biliyorum, ancak (benim gibi) birinin de buna ihtiyacı olabilir.

Etkinliğiniz AppCompatActivity'yi genişletirse , daha basit (iki adımlı) bir çözüm kullanabilirsiniz:

1 - Ev dışı bir parça eklediğinizde, parça işlemini gerçekleştirdikten hemen sonra yukarı düğmesini gösterin. Bunun gibi:

    // ... add a fragment
    // Commit the transaction
    transaction.commit();

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2 - Ardından YUKARI düğmesine basıldığında gizlersiniz.

@Override
public boolean onSupportNavigateUp() {
    getSupportActionBar().setDisplayHomeAsUpEnabled(false);        
    return true;
}

Bu kadar.


7

Roger Garzon Nieto'nun ve sohailaziz'in cevaplarının bir kombinasyonunu kullandım . Uygulamamda tek bir MainActivity ve içine yüklenmiş A, B, C parçaları var. Benim "ev" parçam (A) OnBackStackChangedListener'ı uygular ve backStack'in boyutunu kontrol eder; birden az ise YUKARI düğmesini gizler. B ve C parçaları her zaman geri düğmesini yükler (benim tasarımımda, B A'dan ve C, B'den başlatılır). MainActivity, YUKARI düğmesine dokunulduğunda arka yığınını açar ve parçaların çağırdığı düğmeyi gösterme / gizleme yöntemlerine sahiptir:

Ana aktivite:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        // Respond to the action bar's Up/Home button
        case android.R.id.home:
            getSupportFragmentManager().popBackStack();
            return true;
    }
    return super.onOptionsItemSelected(item);
}

public void showUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(true); }
public void hideUpButton() { getSupportActionBar().setDisplayHomeAsUpEnabled(false); }

fragmentA (FragmentManager.OnBackStackChangedListener'ı uygular):

public void onCreate(Bundle savedinstanceSate) {
    // listen to backstack changes
    getActivity().getSupportFragmentManager().addOnBackStackChangedListener(this);

    // other fragment init stuff
    ...
}

public void onBackStackChanged() {
    // enable Up button only  if there are entries on the backstack
    if(getActivity().getSupportFragmentManager().getBackStackEntryCount() < 1) {
        ((MainActivity)getActivity()).hideUpButton();
    }
}

fragmentB, fragmentC:

public void onCreate(Bundle savedinstanceSate) {
    // show the UP button
    ((MainActivity)getActivity()).showUpButton();

    // other fragment init stuff
    ...
}

5

Bu benim için çalıştı. OnSupportNavigateUp ve onBackPressed'i geçersiz kılın, örneğin (Kotlin'deki kod);

override fun onBackPressed() {
    val count = supportFragmentManager.backStackEntryCount
    if (count == 0) {
        super.onBackPressed()
    } else {
        supportFragmentManager.popBackStack()
    }
}

override fun onSupportNavigateUp(): Boolean {
    super.onSupportNavigateUp()
    onBackPressed()
    return true
}

Şimdi parçada, yukarı oku görüntülerseniz

activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)

Üzerine tıklamak sizi önceki aktiviteye geri götürür.


5

Kotlin:

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        supportFragmentManager.addOnBackStackChangedListener { setupHomeAsUp() }
        setupHomeAsUp()
    }

    private fun setupHomeAsUp() {
        val shouldShow = 0 < supportFragmentManager.backStackEntryCount
        supportActionBar?.setDisplayHomeAsUpEnabled(shouldShow)
    }

    override fun onSupportNavigateUp(): Boolean = 
        supportFragmentManager.popBackStack().run { true }

    ...
}

2

Bu çok iyi ve güvenilir bir çözüm: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

Adam backPress davranışını işleyen ve strateji modelini kullanarak aktif parçalar arasında geçiş yapan soyut bir parça oluşturdu.

Bazılarınız için soyut sınıfta küçük bir dezavantaj olabilir ...

Kısaca, bağlantıdaki çözüm şu şekildedir:

// Abstract Fragment handling the back presses

public abstract class BackHandledFragment extends Fragment {
    protected BackHandlerInterface backHandlerInterface;
    public abstract String getTagText();
    public abstract boolean onBackPressed();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(!(getActivity()  instanceof BackHandlerInterface)) {
            throw new ClassCastException("Hosting activity must implement BackHandlerInterface");
        } else {
            backHandlerInterface = (BackHandlerInterface) getActivity();
        }
    }

    @Override
    public void onStart() {
        super.onStart();

        // Mark this fragment as the selected Fragment.
        backHandlerInterface.setSelectedFragment(this);
    }

    public interface BackHandlerInterface {
        public void setSelectedFragment(BackHandledFragment backHandledFragment);
    }
}   

Ve aktivitede kullanım:

// BASIC ACTIVITY CODE THAT LETS ITS FRAGMENT UTILIZE onBackPress EVENTS 
// IN AN ADAPTIVE AND ORGANIZED PATTERN USING BackHandledFragment

public class TheActivity extends FragmentActivity implements BackHandlerInterface {
    private BackHandledFragment selectedFragment;

    @Override
    public void onBackPressed() {
        if(selectedFragment == null || !selectedFragment.onBackPressed()) {
            // Selected fragment did not consume the back press event.
            super.onBackPressed();
        }
    }

    @Override
    public void setSelectedFragment(BackHandledFragment selectedFragment) {
        this.selectedFragment = selectedFragment;
    }
}

Bu bağlantı soruyu cevaplayabilirken, cevabın temel kısımlarını buraya eklemek ve referans için bağlantı sağlamak daha iyidir . Bağlantılı sayfa değişirse yalnızca bağlantı yanıtları geçersiz hale gelebilir.
bummi

BTW: Yinelenenleri belirlerseniz, lütfen onları bu şekilde işaretleyin. Teşekkür.
bummi

onStart içindeSelectedFragment'ı ayarlamak önemli mi?
VLeonovs
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.