用片段回栈处理 ActionBar 标题?

我有一个 Activity,我加载在一个 ListFragment,点击后,它钻下一个水平和一个新类型的 ListFragment显示,取代原来的一个(使用下面的 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();
}
50860 次浏览

在每个片段和每个活动中,我都会像这样更改标题。这样,活动标题总是正确的:

@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来监听宿主 Activity中的后台堆栈更改:

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

然后,识别回调方法中的情况并设置适当的标题,而不需要从 Fragment访问 ActionBar

这是一个更优雅的解决方案,因为 Fragment不需要知道 ActionBar的存在,而且 Activity通常是管理回栈的地方,因此在那里处理它似乎更合适。Fragment在任何时候都应该只考虑它自己的内容,而不是周围的环境。

更多关于 文件主题的内容。

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

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

让控制活动按以下方式完成所有工作:

侦听堆栈事件(在活动的 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);
.
.
.
}

使用碎片法:

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

它在每个片段出现时都会被调用,但在简历中不会。

在背面按下更新操作栏标题

SetTitle (“ title”)

内部 onCreateView 方法。

最好的方法是使用 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 ()方法。在这里,我根据从导航抽屉中选择的选项来显示片段。变量 position 对应于在导航折叠框中从 ListView 或 ReclerView 中单击的项的位置。我使用 getSupportActionBar.setTitle (title)相应地设置了动作栏的标题,其中标题存储相应的标题名称。

每当我们单击导航抽屉中的项目时,就会根据用户单击的项目显示一个片段。但是在后端,这个片段被添加到后端堆栈中,并且 BackStachChanged ()方法遭到攻击。我所做的是创建了一个变量 mPreviousBackStackCount 并将其初始化为0。我还创建了一个额外的堆栈,它将存储操作栏标题名称。每当我向回堆栈中添加一个新片段时,我都会将相应的标题名称添加到我创建的堆栈中。在相反的一边,每当我按下 BackStackChanged ()的后退按钮,调用并从堆栈中弹出最后一个标题名称,然后将标题设置为通过堆栈的 Peak ()方法派生的名称。

例如:

假设我们的机器人回栈是空的:

按导航抽屉中的选项1: OnBackStachChanged ()被调用,片段1被添加到 android 的回堆栈中,backStackEntryCount 被设置为1,而片段1被推送到我的堆栈中,mFragposition tionTitleDisplay 的大小变为1。

按导航抽屉里的选项2: OnBackStachChanged ()被调用,片段2被添加到 android 的回栈中,backStackEntryCount 被设置为2,而片段2被推送到我的堆栈中,mFragposition TitleDisplay 的大小变为2。

现在我们在 android 栈和我的栈中都有2个元素。当您按回退按钮 onBackStackChanged ()时,将调用 backStackEntryCount 的值为1。代码输入 if 部分并从堆栈中弹出最后一个条目。因此,android 回溯只有1个片段——“ Fragment 1”,而我的栈只有1个标题——“ Frag1”。现在我只需从堆栈中查看()标题,并将操作栏设置为该标题。

记住: 要设置 action bat 标题,请使用 Peak ()而不是 pop () ,否则当您打开超过2个片段并试图通过按回退按钮返回时,您的应用程序将崩溃。

最好让操作系统做尽可能多的工作。 假设每个片段都使用. addToBackStack (“ title”)正确命名 你可以重写像这样的 onBackPress 来实现你想要的行为:

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

你可以用 onKeyDown 解决! 我有一块布 Mainisopen = true < —— MainFragment 是可见的 Other 片段 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);
}


}

我使用了与 Lee 上前类似的解决方案,但是替换了 onBackStackChanged()方法。

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

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

如上所述,我的解决方案是将这段代码添加到 MainActivity onCreate method () : 并更改操作栏的标题

FragmentManager fragmentManager=getSupportFragmentManager();
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
Fragment currentFragment = fragmentManager.findFragmentById(R.id.My_Container_1_ID);
currentFragment.onResume();
}
});

并在片段的 onResume ()方法中更改操作栏标题

@Override
public void onResume() {
super.onResume();
AppCompatActivity activity = (AppCompatActivity) getActivity();
ActionBar actionBar = activity.getSupportActionBar();
if(actionBar!=null) {
actionBar.setTitle("Fragment Title");
actionBar.setSubtitle("Subtitle");
}


}