Mit Android 4.2 erhielt die Support-Bibliothek Unterstützung für verschachtelte Fragmente, siehe hier . Ich habe damit herumgespielt und ein interessantes Verhalten / einen Fehler in Bezug auf Backstack und getChildFragmentManager () gefunden . Bei Verwendung von getChildFragmentManager () und addToBackStack (String name) führt das System durch Drücken der Zurück-Taste den Back-Stack nicht zum vorherigen Fragment herunter. Wenn Sie dagegen getFragmentManager () und addToBackStack (String name) verwenden, kehrt das System durch Drücken der Zurück-Taste zum vorherigen Fragment zurück.
Für mich ist dieses Verhalten unerwartet. Durch Drücken der Zurück-Taste auf meinem Gerät erwarte ich, dass das zuletzt dem Back-Stack hinzugefügte Fragment gelöscht wird, selbst wenn das Fragment dem Back-Stack im Kinderfragment-Manager hinzugefügt wurde.
Ist dieses Verhalten korrekt? Ist dieses Verhalten ein Fehler? Gibt es eine Lösung für dieses Problem?
Beispielcode mit getChildFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getChildFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
Beispielcode mit getFragmentManager ():
public class FragmentceptionActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
final FrameLayout wrapper1 = new FrameLayout(this);
wrapper1.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper1.setId(1);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 0;
final TextView text = new TextView(this);
text.setLayoutParams(params);
text.setText("fragment 1");
wrapper1.addView(text);
setContentView(wrapper1);
getSupportFragmentManager().beginTransaction().addToBackStack(null)
.add(1, new Fragment1()).commit();
}
public class Fragment1 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper2 = new FrameLayout(getActivity());
wrapper2.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper2.setId(2);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 100;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 2");
wrapper2.addView(text);
return wrapper2;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(2, new Fragment2()).commit();
}
}
public class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper3 = new FrameLayout(getActivity());
wrapper3.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper3.setId(3);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 200;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 3");
wrapper3.addView(text);
return wrapper3;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(3, new Fragment3()).commit();
}
}
public class Fragment3 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper4 = new FrameLayout(getActivity());
wrapper4.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper4.setId(4);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 300;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 4");
wrapper4.addView(text);
return wrapper4;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getFragmentManager().beginTransaction().addToBackStack(null)
.add(4, new Fragment4()).commit();
}
}
public class Fragment4 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final FrameLayout wrapper5 = new FrameLayout(getActivity());
wrapper5.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
wrapper5.setId(5);
final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
params.topMargin = 400;
final TextView text = new TextView(getActivity());
text.setLayoutParams(params);
text.setText("fragment 5");
wrapper5.addView(text);
return wrapper5;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}
}
Antworten:
Diese Lösung ist möglicherweise eine bessere Version der @ Sean-Antwort:
Wieder habe ich diese Lösung basierend auf der obigen @ Sean-Antwort vorbereitet.
Wie @ AZ13 sagte, ist diese Lösung nur in Situationen mit untergeordneten Fragmenten auf einer Ebene möglich. Im Fall von Fragmenten mit mehreren Ebenen werden die Arbeiten etwas komplexer. Ich empfehle daher, diese Lösung nur in dem von mir genannten realisierbaren Fall auszuprobieren. =)
Hinweis: Da die
getFragments
Methode jetzt eine private Methode ist, funktioniert diese Lösung nicht. Sie können in den Kommentaren nach einem Link suchen, der eine Lösung für diese Situation vorschlägt.quelle
getFragments
ist jetzt öffentlich.Scheint wie ein Fehler. Schauen Sie sich an: http://code.google.com/p/android/issues/detail?id=40323
Für eine Problemumgehung, die ich erfolgreich verwendet habe (wie in den Kommentaren vorgeschlagen):
quelle
Die eigentliche Antwort auf diese Frage ist die Funktion setPrimaryNavigationFragment der Fragmenttransaktion.
Sie müssen diese Funktion für das ursprüngliche übergeordnete Fragment festlegen, wenn die Aktivität es hinzufügt. Ich habe eine replaceFragment-Funktion in meiner Aktivität, die folgendermaßen aussieht:
Dies gibt Ihnen das gleiche Verhalten, als würden Sie von normalem Fragment B zurück zu Fragment A klicken, außer jetzt ist es auch auf den untergeordneten Fragmenten!
quelle
Diese Lösung ist möglicherweise eine bessere Version von @ismailarilik. Antwort:
Verschachtelte Fragmentversion
quelle
SupportFragmentManager
und stattdessen nur den Standard zu verwendenFragmentManager
?Mit dieser Antwort wird die rekursive Rückprüfung durchgeführt und jedem Fragment die Möglichkeit gegeben, das Standardverhalten zu überschreiben. Dies bedeutet, dass Sie ein Fragment, das einen ViewPager hostet, dazu bringen können, etwas Besonderes zu tun, z. B. zu der Seite zu scrollen, die als Backstack dient, oder zur Startseite zu scrollen und dann beim nächsten Zurück drücken Sie Beenden.
Fügen Sie dies Ihrer Aktivität hinzu, die AppCompatActivity erweitert.
Fügen Sie dies Ihrem BaseFragment oder der Klasse hinzu, von der Sie alle Ihre Fragmente erben lassen können.
quelle
Dieser Code navigiert durch den Baum der Fragmentmanager und gibt den zuletzt hinzugefügten zurück, der alle Fragmente enthält, die vom Stapel entfernt werden können:
Rufen Sie die Methode auf:
quelle
Der Grund dafür ist, dass Ihre Aktivität von FragmentActivity abgeleitet ist, die den Tastendruck BACK verarbeitet (siehe Zeile 173 von FragmentActivity) .
In unserer Anwendung verwende ich einen ViewPager (mit Fragmenten) und jedes Fragment kann verschachtelte Fragmente haben. Ich habe damit umgegangen:
void onBackKeyPressed()
Beachten Sie auch, dass ich
getChildFragmentManager()
in den Fragmenten Fragmente richtig verschachtele. Sie können eine Diskussion und eine Erklärung in diesem Beitrag von Android-Entwicklern sehen .quelle
Wenn Sie Fragment in einem Fragment verwenden, verwenden Sie
getChildFragmentManager()
Wenn Sie ein untergeordnetes Fragment verwenden und es ersetzen, verwenden Sie
getParentFragmentManager()
Wenn beide nicht für Sie arbeiten, versuchen Sie dies
getActivity().getSupportFragmentManager()
quelle
Ich war in der Lage, Fragment-Back-Stack zu verarbeiten, indem ich diese Methode bei der onCreate View () -Methode zum übergeordneten Fragment hinzufügte und die Stammansicht übergab.
Die Methode isEnableFragmentBackStack () ist ein boolesches Flag, um zu wissen, wann ich mich auf dem Hauptfragment oder dem nächsten befinde.
Stellen Sie sicher, dass Sie beim Festschreiben des Fragments, für das ein Stapel vorhanden sein muss, die Methode addToBackstack hinzufügen müssen.
quelle
Diese Lösung ist möglicherweise besser, da sie alle Ebenen verschachtelter Fragmente überprüft:
In Ihrer Aktivität können
onBackPressed
Sie es einfach so nennen:quelle
Vielen Dank an alle für ihre Hilfe, diese (optimierte Version) funktioniert für mich:
HINWEIS: Möglicherweise möchten Sie auch die Hintergrundfarbe dieser verschachtelten Fragmente auf die Hintergrundfarbe des Fensterfensters des App-Themas einstellen, da diese standardmäßig transparent sind. Etwas außerhalb des Rahmens dieser Frage, aber dies wird erreicht, indem das Attribut android.R.attr.windowBackground aufgelöst und der Hintergrund der Fragmentansicht auf diese Ressourcen-ID gesetzt wird.
quelle
Mehr als 5 Jahre und dieses Thema ist immer noch relevant. Wenn Sie fragmentManager.getFragments () aufgrund seiner Einschränkung nicht verwenden möchten. Erweitern und verwenden Sie die folgenden Klassen:
NestedFragmentActivity.java
NestedFragment.java
Erläuterung:
Jede Aktivität und jedes Fragment, die aus den oben genannten Klassen erweitert wurden, verwaltet ihren eigenen Backstack für jedes ihrer Kinder und Kinderkinder und so weiter. Der Backstack ist einfach eine Aufzeichnung von "aktiven Fragment" -Tags / IDs. Die Einschränkung besteht also darin, immer ein Tag und / oder eine ID für Ihr Fragment bereitzustellen.
Wenn Sie in einem childFragmentManager zum Backstack hinzufügen, müssen Sie auch "addToParentBackStack ()" aufrufen. Dadurch wird sichergestellt, dass das Tag / die ID des Fragments für spätere Popups zum übergeordneten Fragment / zur übergeordneten Aktivität hinzugefügt wird.
Beispiel:
quelle
Ich habe es richtig implementiert, wenn jemand bis jetzt keine Antwort gefunden hat
Fügen Sie diese Methode einfach zu Ihrem untergeordneten verschachtelten Fragment hinzu
quelle
Ich habe dieses Problem gelöst, indem ich das aktuell geöffnete Fragment im Eigentum der Aktivität gehalten habe. Dann überschreibe ich die Methode
Auf diese Weise füge ich ein untergeordnetes Fragment aus sich selbst in das aktuell geöffnete Fragment ein.
Dies ist das XML-Layout des übergeordneten Fragments und des hinzugefügten Fragments
quelle
Nachdem ich einige der hier vorgestellten Lösungen beobachtet hatte, stellte ich fest, dass ich eher eine solche Implementierung verwende, um dem übergeordneten Fragment Flexibilität und Kontrolle darüber zu ermöglichen, wann der Stapel geöffnet wird oder wann die Rückaktion ignoriert werden soll:
Definieren einer "ParentFragment" -Schnittstelle:
}}
Überschreiben von "onBackPressed" in der übergeordneten Aktivität (oder in der BaseActivity):
Lassen Sie dann das übergeordnete Fragment so behandeln, wie es möchte, zum Beispiel:
Auf diese Weise können Sie vermeiden, dass Sie glauben, dass ein legitimes untergeordnetes Fragment entfernt werden muss, wenn Sie beispielsweise einen Ansichtspager verwenden (und die Anzahl der Backstack-Einträge> 0).
quelle
Wenn Sie eine haben,
DialogFragment
die wiederum verschachtelte Fragmente enthält, ist die 'Problemumgehung' etwas anders. Anstatt einonKeyListener
auf das zu setzenrootView
, müssen Sie dies mit dem tunDialog
. Außerdem werden Sie eineDialogInterface.OnKeyListener
und nicht dieView
eine einrichten. Natürlich, denk dranaddToBackStack
!Folgendes müssen Sie im onCreateDialog tun
quelle
Dialog
(nichtDialogFragment
) und der von Ihnen verwendete Listener istDialogInterface.OnKeyListener
- der Code funktioniert und ist vollständig (und wird verwendet). Warum geben Sie nicht Ihre Situation an und vielleicht kann ich helfen.für ChildFragments funktioniert das ..
quelle