74

我有一个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();
}
4

11 回答 11

124

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

@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);
    }
}
于 2012-11-20T12:25:29.807 回答
28

由于原始答案已经很老了,这也可能会有所帮助。正如文档所述,可能需要注册一个listener来监听主机中的后端堆栈更改Activity

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

然后,在回调方法中识别情况并设置适当的标题,而无需ActionBarFragment.

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

更多关于文档中的主题。

于 2014-04-23T07:55:43.377 回答
11

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

监听 backstack 事件(在活动的 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);
    .
    .
    .
}
于 2014-10-09T08:46:58.477 回答
7

Warpzit 是对的。这也解决了更改设备方向时的标题问题。此外,如果您将 support v7 用于操作栏,您可以从片段中获取操作栏,如下所示:

@Override
public void onResume() {
    super.onResume();
    ((ActionBarActivity)getActivity()).getSupportActionBar().setTitle("Home");
}
于 2014-07-10T10:44:04.600 回答
7

最好让操作系统做尽可能多的工作。假设每个片段都使用 .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);
    }
}
于 2015-11-15T04:22:44.967 回答
5

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

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

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

然后我覆盖该onBackStackChanged()方法并setTitle()使用最后一个 backstack 条目名称进行调用。

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

    setTitle(lastBackStackEntry.getName());
}
于 2016-09-06T12:53:48.847 回答
4

使用片段方法:

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

每次出现 Fragment 时都会调用它,但 onResume 不会。

于 2015-04-23T20:49:46.547 回答
1

最好的方法是利用 android 提供的接口 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() 方法。这里我根据从导航抽屉中选择的选项显示片段。变量位置对应于从导航抽屉中的ListView或RecyclerView单击的项目的位置。我使用 getSupportActionBar.setTitle(title) 相应地设置了操作栏标题,其中标题存储了适当的标题名称。

每当我们从导航抽屉中单击项目时,都会根据单击给用户的项目显示一个片段。但是在后端,这个片段被添加到 backstack 并且方法 onBackStachChanged() 被命中。我所做的是我创建了一个变量 mPreviousBackStackCount 并将其初始化为 0。我还创建了一个额外的堆栈来存储操作栏标题名称。每当我向后台堆栈添加一个新片段时,我都会将相应的标题名称添加到我创建的堆栈中。在另一侧,每当我按下后退按钮时,都会调用 onBackStackChanged(),并从堆栈中弹出最后一个标题名称,并将标题设置为堆栈的 peek() 方法派生的名称。

例子:

假设我们的 android backstack 是空的:

从导航抽屉中按选择 1:调用 onBackStachChanged() 并将 Fragment 1 添加到 android backstack,backStackEntryCount 设置为 1,将 Frag1 推送到我的堆栈,并且 mFragPositionTitleDisplayed 的大小变为 1。

从导航抽屉中按选择 2:调用 onBackStachChanged() 并将 Fragment 2 添加到 android backstack,backStackEntryCount 设置为 2,并将 Frag2 推送到我的堆栈中,并且 mFragPositionTitleDisplayed 的大小变为 2。

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

请记住:要设置动作蝙蝠标题使用 peek() 而不是 pop() 否则当您打开超过 2 个片段并尝试按返回按钮返回时,您的应用程序将崩溃。

于 2015-07-04T18:40:30.907 回答
1

您可以使用 onKeyDown 解决!我有一个 bool mainisopen=true <-- MainFragment is Visible other Fragment 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);
    }

}
于 2016-06-06T11:10:41.880 回答
0

如此处所述我的解决方案是将此代码添加到 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");
    }

}
于 2019-09-05T05:24:54.043 回答
-3

在后按时更新操作栏标题。简单地说

getActivity.setTitle("标题")

在 onCreateView 方法中。

于 2015-05-28T13:34:19.043 回答