wake-up-neo.com

Aktionsleiste zur Navigation mit Fragmenten

Ich habe ein Actionbar/Viewpager-Layout mit drei Registerkarten: A , B , und C . Auf der Registerkarte C (Fragment) füge ich ein weiteres Fragment hinzu, beispielsweise Fragment D . mit

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

Ich ändere die Aktionsleiste in DFragments onResume, um die Schaltfläche "Hinzufügen" hinzuzufügen:

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

Wenn ich jetzt in DFragment auf die Schaltfläche Hardware (Telefon) Zurück drücke, kehre ich mit ausgewähltem CFragment zum ursprünglichen Layout mit Registerkarten (ABC) zurück. Wie kann ich diese Funktionalität mit der Aktionsleiste erreichen?

82
SohailAziz

Implementieren Sie OnBackStackChangedListener und fügen Sie diesen Code zu Ihrer Fragmentaktivität hinzu.

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

Ich habe es verstanden. Überschreiben Sie einfach onOptionsItemSelected in der Hosting-Aktivität und öffnen Sie den Backstack, z.

public boolean onOptionsItemSelected(MenuItem item) {

  switch (item.getItemId()) {
   case Android.R.id.home:
     FragmentManager fm = getSupportFragmentManager();
     if (fm.getBackStackEntryCount() > 0) {
          fm.popBackStack();
        }
        return true;
    default:
        return super.onOptionsItemSelected(item);;
    }
}

Rufen Sie getActionBar().setDisplayHomeAsUpEnabled(boolean); und getActionBar().setHomeButtonEnabled(boolean); in onBackStackChanged() auf, wie in einer Antwort unten erläutert.

37
SohailAziz

Wenn Sie eine übergeordnete Aktivität haben und diese Aufwärtsschaltfläche als Zurückschaltfläche verwenden möchten, können Sie diesen Code verwenden:

fügen Sie dies zu onCreate in Ihrer Hauptaktivitätsklasse hinzu

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

    });

und dann fügen Sie onOptionsItemSelected wie folgt hinzu:

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

Ich benutze dies im Allgemeinen die ganze Zeit und scheint ziemlich legitim zu sein

18
Daniel Jonker

sie können mit der Aufwärts-Taste wie mit der Zurück-Taste zurückgehen.

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

Ich weiß, diese Frage ist alt, aber vielleicht braucht jemand (wie ich) sie auch.

Wenn sich Ihre Aktivität auf AppCompatActivity erstreckt, können Sie eine einfachere (zweistufige) Lösung verwenden:

1 - Wenn Sie ein Nicht-Ausgangsfragment hinzufügen, zeigen Sie direkt nach dem Festschreiben der Fragmenttransaktion die Aufwärtsschaltfläche an. So was:

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

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

2 - Wenn Sie die UP-Taste drücken, wird diese ausgeblendet.

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

Das ist es.

8

Ich habe eine Kombination aus Roger Garzon Nietos und sohailazizs Antworten verwendet. Meine App verfügt über eine einzelne MainActivity und Fragmente A, B, C, die in sie geladen werden. Mein "Home" -Fragment (A) implementiert OnBackStackChangedListener und überprüft die Größe des BackStack. Wenn es weniger als eins ist, wird die UP-Taste ausgeblendet. Fragmente B und C laden immer den Zurück-Button (in meinem Design wird B von A und C von B gestartet). Die MainActivity selbst öffnet beim Drücken der UP-Taste lediglich den Backstack und verfügt über Methoden zum Ein-/Ausblenden der Schaltfläche, die von den Fragmenten aufgerufen wird:

Hauptaktivität:

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 (implementiert FragmentManager.OnBackStackChangedListener):

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

Fragment B, Fragment C:

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

    // other fragment init stuff
    ...
}
6
verboze

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 }

    ...
}
5
fada21

Das hat bei mir funktioniert. Überschreiben Sie beispielsweise onSupportNavigateUp und onBackPressed (Code in Kotlin);

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

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

Jetzt im Fragment, wenn Sie den Aufwärtspfeil anzeigen

activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)

Wenn Sie darauf klicken, kehren Sie zur vorherigen Aktivität zurück.

4
bebe

Dies ist eine sehr gute und zuverlässige Lösung: http://vinsol.com/blog/2014/10/01/handling-back-button-press-inside-fragments/

Der Typ hat ein abstraktes Fragment erstellt, das das Verhalten von backPress behandelt und mithilfe des Strategiemusters zwischen den aktiven Fragmenten wechselt.

Für einige von euch gibt es vielleicht ein kleines Manko in der abstrakten Klasse ...

In Kürze lautet die Lösung über den Link wie folgt:

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

Und Verwendung in der Aktivität:

// 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;
    }
}
2
Amio.io