处理ActionBar标题与片段回栈?

我有一个Activity ,我在一个ListFragment加载,点击后,它向下钻取一个级别,并显示一个新types的ListFragment ,replace原来的(使用下面的showFragment方法)。 这是放在后面的堆栈。

在开始时,活动在操作栏中显示默认标题(即,它基于应用程序的android:label自动设置)。

当显示层次结构中下一级的列表时,单击的项目名称应该成为操作栏的标题。

但是,按Back时 ,我想要恢复原来的默认标题。 这不是FragmentTransaction知道的事情,所以标题不会被恢复。

我隐约看了FragmentBreadCrumbs ,但这似乎需要使用自定义视图。 我使用ActionBarSherlock,并希望没有我自己的自定义标题视图。

这样做的最好方法是什么? 是否有可能没有一个样板代码的负载,并不得不跟踪在途中显示的标题?


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

在每一个片段和每一个活动中,我改变这样的标题。 这样活跃的标题将永远是正确的:

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

有一些情况下,onResume不被称为内部片段。 在其中一些情况下,我们可以使用:

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

原来的答案很古老,也可能有帮助。 正如文档所述,可能需要注册一个listener来监听托pipeActivity的后退栈变化:

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

然后,确定callback方法中的情况并设置正确的标题,而不必从Fragment访问ActionBar

这是一个更加优雅的解决scheme,因为Fragment不需要知道ActionBar存在,而Activity通常是pipe理后台堆栈的地方,所以在那里处理它似乎更合适。 在任何时候都应该只考虑Fragment的内容,而不是环境。

更多关于文档中的主题。

让控制活动做所有的工作如下:

聆听backstack事件(在activity的onCreate()中):

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

从容器中获取当前片段:

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

在内容视图中设置片段:

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

Warpzit是对的。 当设备的方向改变时,这也解决了标题问题。 另外,如果你使用支持v7的动作栏,你可以从这样的片段获得操作栏:

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

最好让操作系统做尽可能多的工作。 假设每个片段使用.addToBackStack(“title”)正确命名,那么你可以重写onBackPressed这样的事情来实现所需的行为:

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

我使用Lee方法的类似解决scheme,而是replaceonBackStackChanged()方法。

首先,我将事务添加到后端堆栈时设置了片段名称。

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

然后我重写onBackStackChanged()方法,并用最后一个后台条目名称调用setTitle()

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

使用片段方法:

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

它被称为每个片段外观,但onResume不是。

最好的方法是利用android提供的Interface OnBackStackChangedListener方法onBackStackChanged()。

比方说,我们有一个导航抽屉,用户可以导航到4个选项。 在这种情况下,我们将有4个片段。 让我们先看代码,然后我会解释工作。

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

在显示的代码中,我们有了displayFragment()方法。 在这里,我根据从导航抽屉中select的选项来显示片段。可变位置对应于从导航抽屉中的ListView或RecyclerView中点击的项目的位置。 我相应地使用getSupportActionBar.setTitle(title)设置操作栏标题,标题存储相应的标题名称。

每当我们从导航器中点击项目时,就会显示一个片段,这取决于用户点击的项目。 但是在后端这个片段被添加到了堆栈,并且方法onBackStachChanged()被击中。 我所做的是我已经创build了一个variablesmPreviousBackStackCount并将其初始化为0.我还创build了一个额外的堆栈来存储操作栏标题名称。 每当我添加一个新的片段到堆栈,我添加相应的标题名称到我创build的堆栈。 每当我按下后退buttononBackStackChanged()被调用,而我从我的堆栈中popup最后的标题名称,并将标题设置为由堆栈的peek()方法派生的名称。

例:

比方说,我们的android后台堆栈是空的:

按导航抽屉的select1:onBackStachChanged()被调用,片段1被添加到android的backstack,backStackEntryCount被设置为1,Frag1被推到我的堆栈和mFragPositionTitleDisplayed的大小变成1。

按导航的抽屉select2:onBackStachChanged()被调用,片段2被添加到android的backstack,backStackEntryCount被设置为2,Frag2被推到我的堆栈和mFragPositionTitleDisplayed的大小变成2。

现在我们在android堆栈和堆栈中都有两个元素。 当你按下callbackbuttononBackStackChanged()被调用,并且backStackEntryCount的值是1.代码进入if部分,并从我的堆栈popup最后一个条目。 所以,android的堆栈只有一个片段 – “片段1”,我的堆栈只有一个标题 – “Frag1”。 现在,我只是从我的堆栈偷看()标题,并设置操作栏为该标题。

记住:要设置动作蝙蝠标题使用peek()而不是popup()否则你的应用程序将崩溃,当你打开2个以上的片段,并尝试返回按回来button。

你的手杖解决onKeyDown! 我有一个布尔mainisopen = true <MainFragment是可见的其他片段mainisopen = false

这里是我的代码:

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

要更新后面的操作栏标题。 只是简单地说

getActivity.setTitle( “标题”)

里面的onCreateView方法。