处理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方法。