我面临的情况是,在我的应用程序中,我有一个单一窗格和双窗格样式布局。对于每种不同的布局样式,我使用的功能可以在给定所需的屏幕时正确设置布局,而不是单独处理屏幕之间可能的每一个导航操作。
它基本上是应用程序中每个屏幕的switch
语句,每个屏幕都有一个嵌套的switch
语句来处理每种布局样式。这就是我在代码中所说的:
protected void setupScreen() {
switch(currentScreen) {
case SCREEN_ONE:
switch(currentLayout) {
case SINGLE_PANE:
// Perform actions to setup the screen
break;
case DUAL_PANE:
// Perform actions to setup the screen
break;
}
break;
case SCREEN_TWO:
switch(currentLayout) {
case SINGLE_PANE:
// Perform actions to setup the screen
break;
case DUAL_PANE:
// Perform actions to setup the screen
break;
}
break
// ... etc ....
}
}
在我想执行设置屏幕的操作的部分中,这包括以下基本的三个操作:
// Create the fragments if necessary
if (screenFragment == null) {
screenFragment = new myFragment();
}
// Remove the existing fragments from the layout views
// HOW???
// Add the fragments for this screen to the view
getSupportFragmentManager().beginTransaction().add(pane1.getId(), myFragment, "myFragment").commit();
正如您所看到的,我正在努力的第二步是如何。 如何删除给定Fragment
中的所有View
,而不知道您要删除哪些FragmentTransaction.replace()
?我找到的最接近的是Fragment
,它确实成功地为每个案例但成功执行此操作,结果发现您正在用相同的片段替换FragmentTransaction.replace()
。在这种情况下,它不会删除所有,然后添加(如文档建议),它似乎删除。这是使用兼容性库的问题还是不应该使用removeAllFragments()
的方式?
无论如何,我该怎么做呢?我是否必须对FragmentTransaction.replace()
函数进行编码以遍历每个片段并将其分离,或者是否有办法执行'二合一'{{1}}函数声称要执行的操作的前半部分?
答案 0 :(得分:19)
其他答案都没有真正对我有用。这就是我的所作所为:
List<Fragment> al = getSupportFragmentManager().getFragments();
if (al == null) {
// code that handles no existing fragments
return;
}
for (Fragment frag : al)
{
// To save any of the fragments, add this check.
// A tag can be added as a third parameter to the fragment when you commit it
if (frag == null || frag.getTag().equals("<tag-name>")) {
continue;
}
getSupportFragmentManager().beginTransaction().remove(frag).commit();
}
或者,如果您被迫使用它(但不推荐):
.commitAllowingStateLoss();
此外,如果您多次从视图中删除所有片段,您可以考虑检查当前片段是否为空或isDetached()
或isRemoving()
,或者您可能会NullPointerExceptions
}。
更新:getSupportFragmentManger().getFragments()
的文档现在显然是hidden,但在我的代码中仍能正常运行。这是文档的屏幕截图:
话虽如此,由于它是隐藏的,因此不再需要使用此方法,请参阅下面的更新。
更新8-4-15 :如果您没有使用支持库获取片段,很遗憾没有getFragments()
可用,但仍有一对,更多不方便,选择。
fragment
提供tag
或id
,并根据需要对其进行迭代以处理每个fragment
。onAttachListener
创建一个监听器,因此每次将新fragment
附加到activity
时,您都可以存储fragment
,然后遍历该数据结构根据需要处理每个fragment
。如果不使用getSupportFragmentManager()
,要处理交易,您需要使用getFragmentManager()
。
答案 1 :(得分:7)
典型的机制是使用FragmentManager.findFragmentByTag()
。您可以使用它并将标签添加到您的片段(或id的替代品)。这样您就可以确定当前正在管理的片段。然后,一旦你有一个当前片段的句柄(findFragmentByTag返回非null),你可以使用FragmentManager.beginTransaction()
启动一个FrgamentTransaction并删除/添加必要的片段。以这种方式工作将允许您避免要保留的片段的“重新添加”过程。
我可能会做的是这样的代码:(警告伪代码)
Fragment pane1 = FragmentManager.findFragmentByTag("myFragmentPane1");
Fragment pane2 = FragmentManager.findFragmentByTag("myFragmentPane2");
setupScreen(pane1, pane2);
您还应该考虑班级的子类,而不是“一个班级中的所有内容”。你有一个相当明显的案例是Martin Fowler的Replace Conditional with Subclass。否则,我担心当您添加另一个屏幕时,管理员会非常难以接受。
答案 2 :(得分:3)
如果你使用 android.support.v4.app.Fragment ,你可以这样做:
List<Fragment> fragments = getSupportFragmentManager().getFragments();
if (fragments != null) {
for (Fragment fragment : fragments) {
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
}
}
答案 3 :(得分:1)
结果FragmentTransaction.replace()
是正确的操作,应该可以正常工作。它只在使用ActionBarSherlock
和SherlockFragmentActivity
时不起作用,所以我只能假设它是此兼容性库中的错误。
我通过使用下面的代码确认了这一点,通过API on API11 +,Android兼容性库和ActionBarSherlock实现了所需的行为。它只会在最后一个例子中中断。
package com.test.test;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import android.os.Bundle;
import android.content.Context;
import android.graphics.Color;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;
public class MainActivity extends SherlockFragmentActivity {
// Consistent fragment instance
myFragment myFrag = null;
// Views
FrameLayout fl = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.VERTICAL);
Button b = new Button(this);
b.setText("Repeat");
b.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// Reattach the same fragment
getSupportFragmentManager().beginTransaction().replace(fl.getId(), myFrag).commit();
}
});
fl = new FrameLayout(this);
fl.setId(200);
fl.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
myFrag = new myFragment();
getSupportFragmentManager().beginTransaction().add(fl.getId(), myFrag).commit();
ll.addView(b);
ll.addView(fl);
setContentView(ll);
}
public static class myFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
TextView tv = new TextView(getActivity());
tv.setText("My fragment");
tv.setGravity(Gravity.CENTER);
tv.setBackgroundColor(Color.RED);
return tv;
}
}
}
答案 4 :(得分:0)
这或多或少是我处理这个问题的方法。让所有片段实现类似的接口:
public interface NamedFragment{
public FragmentName getFragmentName();
}
制作与你的片段相对应的枚举:
public enum FragmentName{
SOME_FRAGMENT,
SOME_OTHER_FRAGMENT;
}
然后在你的片段切换活动中:
// Get the manager and transaction separately so you can use both:
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
// Get a reference to the fragment(s) currently in the container(s)
Fragment currentFragment = fragmentManager.findFragmentById(position);
FragmentName cFragmentName =
((NamedFragment) currentFragment).getFragmentName();
Fragment nextFragment =
Fragment.instantiate(this, some_new_fragment_string);
FragmentName nFragmentName =
((NamedFragment) nextFragment).getFragmentName();
// Compare the "names"
if(cFragmentName != nFragmentName){
ft.replace(position, nextFragment);
}
你必须改变一些东西以适合你的细节。