wake-up-neo.com

Behandlung von ActionBar-Titeln mit dem Fragment-Backstack?

Ich habe ein Activity, in das ich ein ListFragment lade. Wenn ich darauf klicke, wird eine Ebene nach unten gebohrt und ein neuer Typ von ListFragment wird angezeigt, wobei der ursprüngliche ersetzt wird (mithilfe von die showFragment Methode unten). Dies wird auf den hinteren Stapel gelegt.

Zu Beginn der Aktivität wird der Standardtitel in der Aktionsleiste angezeigt (d. H. Er wird automatisch basierend auf dem Android:label Der Anwendung festgelegt).

Wenn Sie die Liste für die nächste Ebene in der Hierarchie anzeigen, sollte der Name des angeklickten Elements der Titel der Aktionsleiste sein.

Beim Drücken von BackIch möchte, dass der ursprüngliche Standardtitel wiederhergestellt wird. Dies ist nicht etwas, von dem FragmentTransaction weiß, daher wird der Titel nicht wiederhergestellt.

Ich habe vage über FragmentBreadCrumbs gelesen, aber dies erfordert anscheinend die Verwendung einer benutzerdefinierten Ansicht. Ich verwende ActionBarSherlock und würde es vorziehen, keine eigene benutzerdefinierte Titelansicht zu haben.

Wie geht das am besten? Ist es möglich, ohne jede Menge Kesselschild-Code die Titel, die auf dem Weg gezeigt werden, im Auge zu behalten?


protected void showFragment(Fragment f) {
  FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
  ft.replace(R.id.fragment_container, f);
  ft.addToBackStack(null);
  ft.commit();
}
72
Christopher Orr

In jedem Fragment und jeder Aktivität ändere ich den Titel so. Auf diese Weise ist der aktive Titel immer korrekt:

@Override
public void onResume() {
    super.onResume();
    // Set title
    getActivity().getActionBar()
        .setTitle(R.string.thetitle);
}

In einigen Fällen wird onResume nicht in Fragmenten aufgerufen. In einigen dieser Fälle können wir verwenden:

public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisibleToUser) {
        // Set title
        getActivity().getActionBar()
            .setTitle(R.string.thetitle);
    }
}
120
Warpzit

Da die ursprüngliche Antwort ziemlich alt ist, könnte dies ebenfalls hilfreich sein. Wie in der Dokumentation angegeben, kann es sinnvoll sein, ein listener zu registrieren, um die Änderungen des Backstacks im Hosting Activity zu überwachen:

getSupportFragmentManager().addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
            public void onBackStackChanged() {
                // Update your UI here.
            }
        });

Identifizieren Sie dann die Situation in der Rückrufmethode und legen Sie einen richtigen Titel fest, ohne über ActionBar auf Fragment zuzugreifen.

Dies ist eine elegantere Lösung, da der Fragment nichts über die Existenz von ActionBar wissen muss und Activity normalerweise der Ort ist, an dem der Backstack verwaltet wird, damit er abgewickelt wird es scheint angemessener zu sein. Fragment sollte zu jeder Zeit nur von seinem eigenen Inhalt betrachtet werden, nicht von der Umgebung.

Mehr zum Thema in der Dokumentation .

27
Maciej Pigulski

Lassen Sie die Controlling-Aktivität die gesamte Arbeit wie folgt ausführen:

Auf Backstack-Ereignisse warten (in onCreate () der Aktivität):

// Change the title back when the fragment is changed
    getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            Fragment fragment = getFragment();
            setTitleFromFragment(fragment);
        }
    });

Holen Sie sich das aktuelle Fragment aus dem Container:

/**
 * Returns the currently displayed fragment.
 * @return
 *      Fragment or null.
 */
private Fragment getFragment() {
    Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.container);
    return fragment;
}

Legen Sie das Fragment in der Inhaltsansicht fest:

private void setFragment(Fragment fragment, boolean addToBackStack) {
    // Set the activity title
    setTitleFromFragment(fragment);
    .
    .
    .
}
11
Meanman

Warpzit ist richtig. Dies löst auch das Titelproblem, wenn die Ausrichtung des Geräts geändert wird. Auch wenn Sie Support v7 für die Aktionsleiste verwenden, können Sie die Aktionsleiste wie folgt aus dem Fragment abrufen:

@Override
public void onResume() {
    super.onResume();
    ((ActionBarActivity)getActivity()).getSupportActionBar().setTitle("Home");
}
7

Es ist am besten, das Betriebssystem so weit wie möglich arbeiten zu lassen. Unter der Annahme, dass jedes Fragment mit .addToBackStack ("title") richtig benannt ist, können Sie onBackPressed wie folgt überschreiben, um das gewünschte Verhalten zu erzielen:

// this example uses the AppCompat support library
// and works for dynamic fragment titles
@Override
public void onBackPressed() {
    FragmentManager fragmentManager = getSupportFragmentManager();
    int count = fragmentManager.getBackStackEntryCount();
    if (count <= 1) {
        finish();
    }
    else {
        String title = fragmentManager.getBackStackEntryAt(count-2).getName();
        if (count == 2) {
            // here I am using a NavigationDrawer and open it when transitioning to the initial fragment
            // a second back-press will result in finish() being called above.
            mDrawerLayout.openDrawer(mNavigationDrawerFragment.getView());
        }
        super.onBackPressed();
        Log.v(TAG, "onBackPressed - title="+title);
        getSupportActionBar().setTitle(title);
    }
}
6
Lee Hounshell

Ich verwende eine ähnliche Lösung wie Lee-Ansatz , ersetze jedoch stattdessen die onBackStackChanged() -Methode.

Zuerst setze ich den Fragmentnamen, wenn ich die Transaktion zum Backstack hinzufüge.

getSupportFragmentManager().beginTransaction()
                .replace(R.id.frame_content, fragment)
                .addToBackStack(fragmentTitle)
                .commit();

Dann überschreibe ich die Methode onBackStackChanged() und rufe setTitle() mit dem Namen des letzten Backstack-Eintrags auf.

@Override
public void onBackStackChanged() {
    int lastBackStackEntryCount = getSupportFragmentManager().getBackStackEntryCount() - 1;
    FragmentManager.BackStackEntry lastBackStackEntry =
            getSupportFragmentManager().getBackStackEntryAt(lastBackStackEntryCount);

    setTitle(lastBackStackEntry.getName());
}
5
Gnzlt

Verwenden Sie die Fragmentmethode:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)

Es wird bei jedem Fragment-Auftritt aufgerufen, bei onResume jedoch nicht.

4

Sie können mit onKeyDown lösen! Ich habe ein Bool mainisopen = true <- MainFragment ist sichtbar andere Fragment mainisopen = false

und hier ist mein Code:

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && mainisopen == false) {
        mainisopen = true;
        HomeFrag fragment = new HomeFrag();
        FragmentTransaction fragmentTransaction =
                getSupportFragmentManager().beginTransaction();
        fragmentTransaction.replace(R.id.fragmet_cont, fragment);
        fragmentTransaction.commit();
        navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.getMenu().findItem(R.id.nav_home).setChecked(true);
        navigationView.setNavigationItemSelectedListener(this);
        this.setTitle("Digi - Home"); //Here set the Title back
        return true;
    } else {
        if (keyCode == KeyEvent.KEYCODE_BACK && mainisopen == true) {
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setMessage("Wollen sie die App schliessen!");
            builder.setCancelable(true);

            builder.setPositiveButton("Ja!", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    System.exit(1);
                }
            });

            builder.setNegativeButton("Nein!", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    Toast.makeText(getApplicationContext(), "Applikation wird fortgesetzt", Toast.LENGTH_SHORT).show();
                }
            });

            AlertDialog dialog = builder.create();
            dialog.show();

            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

}
1
BitDEVil2K16

Am besten verwenden Sie die Android mitgelieferte Schnittstelle OnBackStackChangedListener-Methode onBackStackChanged ().

Nehmen wir an, wir haben eine Navigationsleiste mit 4 Optionen, zu denen der Benutzer navigieren kann. In diesem Fall haben wir 4 Fragmente. Lassen Sie uns zuerst den Code sehen und dann werde ich die Arbeitsweise erklären.

    private int mPreviousBackStackCount = 0;
    private String[] title_name = {"Frag1","Frag2","Frag3","Frag4"};
    Stack<String> mFragPositionTitleDisplayed;

    public class MainActivity extends ActionBarActivity implements FragmentManager.OnBackStackChangedListener
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ....
    ....
    ....
    getSupportFragmentManager().addOnBackStackChangedListener(this);
    mFragPositionTitleDisplayed = new Stack<>();
}

public void displayFragment() {
    Fragment fragment = null;
    String title = getResources().getString(R.string.app_name);
    switch (position) {
        case 0:
            fragment = new Fragment1();
            title = title_name[position];
            break;
        case 1:
            fragment = new Fragment2();
            title = title_name[position];
            break;
        case 2:
            fragment = new Fragment3();
            title = title_name[position];
            break;
        case 3:
            fragment = new Fragment4();
            title = title_name[position];
            break;
        default:
            break;
    }
    if (fragment != null) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction()
                .replace(R.id.container_body, fragment)
                .addToBackStack(null)
                .commit();
        getSupportActionBar().setTitle(title);
    }
}

@Override
public void onBackStackChanged() {
    int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
    if(mPreviousBackStackCount >= backStackEntryCount) {
        mFragPositionTitleDisplayed.pop();
        if (backStackEntryCount == 0)
            getSupportActionBar().setTitle(R.string.app_name);
        else if (backStackEntryCount > 0) {
            getSupportActionBar().setTitle(mFragPositionTitleDisplayed.peek());
        }
        mPreviousBackStackCount--;
    }
    else{
        mFragPositionTitleDisplayed.Push(title_name[position]);
        mPreviousBackStackCount++;
    }

}   

Im gezeigten Code haben wir die Methode displayFragment (). Hier zeige ich das Fragment auf der Grundlage der in der Navigationsleiste ausgewählten Option an. Die variable Position entspricht der Position des Elements, auf das in der ListView oder RecyclerView in der Navigationsleiste geklickt wurde. Den Titel der Aktionsleiste setze ich entsprechend mit getSupportActionBar.setTitle (title), wobei der Titel den entsprechenden Titelnamen enthält.

Jedes Mal, wenn wir auf ein Objekt in der Navigationsleiste klicken, wird ein Fragment angezeigt, je nachdem, welches Objekt dem Benutzer angeklickt wurde. Auf der Back-End-Seite wird dieses Fragment jedoch zum Backstack hinzugefügt und die Methode onBackStachChanged () wird aufgerufen. Was ich getan habe, ist, dass ich eine Variable mPreviousBackStackCount erstellt und auf 0 initialisiert habe. Ich habe auch einen zusätzlichen Stapel erstellt, in dem die Titelnamen der Aktionsleiste gespeichert werden. Immer wenn ich ein neues Fragment zum Backstack hinzufüge, füge ich meinem erstellten Stack den entsprechenden Titelnamen hinzu. Auf der gegenüberliegenden Seite wird jedes Mal, wenn ich die Zurück-Taste auf BackStackChanged () drücke, der letzte Titelname von meinem Stapel abgerufen und der Titel auf den Namen gesetzt, der von der peek () -Methode des Stapels abgeleitet wurde.

Beispiel:

Nehmen wir an, unser Android Backstack ist leer:

Drücken Sie in der Navigationsleiste Auswahl 1: onBackStachChanged () wird aufgerufen und das Fragment 1 wird zu Android backstack, backStackEntryCount wird auf 1 gesetzt und Frag1 wird auf meinen Stapel verschoben und die Größe von mFragPositionTitleDisplayed wird zu 1.

Drücken Sie Auswahl 2 in der Navigationsleiste: onBackStachChanged () wird aufgerufen und das Fragment 2 wird zu Android backstack, backStackEntryCount wird auf 2 gesetzt und Frag2 wird auf meinen Stapel verschoben und die Größe von mFragPositionTitleDisplayed wird zu 2.

Jetzt haben wir 2 Elemente sowohl im Stapel Android= als auch in meinem Stapel. Wenn Sie den Zurück-Knopf onBackStackChanged () drücken, wird der Wert von backStackEntryCount 1 angezeigt. Der Code gibt den if-Teil ein und springt heraus Der Android) Backstack hat also nur 1 Fragment - "Fragment 1" und mein Stack hat nur 1 Titel - "Frag1". Jetzt sehe ich mir nur den Titel an () von meinem Stapel und setzen Sie die Aktionsleiste auf diesen Titel.

Denken Sie daran: Um den Titel der Action-Fledermaus festzulegen, verwenden Sie peek () und nicht pop (). Andernfalls stürzt Ihre Anwendung ab, wenn Sie mehr als 2 Fragmente öffnen und versuchen, durch Drücken der Zurück-Taste zurückzukehren.

1
Abhishek