在使用片段时,在Android导航抽屉图像和上方插入符号之间切换

当使用导航抽屉时,Android开发人员build议在ActionBar中“只有在导航抽屉中表示的那些屏幕实际上应该具有导航抽屉图像”,并且“所有其他屏幕都具有传统的向上克拉”。

详情请看这里:http: //youtu.be/F5COhlbpIbY

我正在使用一个活动来控制多个片段级别,并且可以让导航抽屉图像在各个级别显示和运行。

在创build较低级别的片段时,我可以调用ActionBarDrawerToggle setDrawerIndicatorEnabled(false)来隐藏导航抽屉图像,并显示“

 LowerLevelFragment lowFrag = new LowerLevelFragment(); //disable the toggle menu and show up carat theDrawerToggle.setDrawerIndicatorEnabled(false); getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout, lowFrag, "lowerFrag").addToBackStack(null).commit(); 

我遇到的问题是,当我导航回顶层的碎片时,上克拉仍然显示,而不是原始的导航抽屉图像。 有关如何“刷新”顶级碎片上的ActionBar以重新显示导航抽屉图像的任何build议?


汤姆的build议为我工作。 以下是我所做的:

主要活动

此活动控制应用程序中的所有片段。

当准备新的片段来replace别人,我设置DrawerToggle setDrawerIndicatorEnabled(false)像这样:

 LowerLevelFragment lowFrag = new LowerLevelFragment(); //disable the toggle menu and show up carat theDrawerToggle.setDrawerIndicatorEnabled(false); getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout, lowFrag).addToBackStack(null).commit(); 

接下来,在onBackPressed的覆盖中,我通过将DrawerToggle设置为setDrawerIndicatorEnabled(true)来恢复上述效果:

 @Override public void onBackPressed() { super.onBackPressed(); // turn on the Navigation Drawer image; // this is called in the LowerLevelFragments setDrawerIndicatorEnabled(true) } 

在LowerLevelFragments中

在片段我修改onCreateonOptionsItemSelected像这样:

onCreate添加了setHasOptionsMenu(true)来启用configuration选项菜单。 还要设置setDisplayHomeAsUpEnabled(true)来启用操作栏中的<

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // needed to indicate that the fragment would // like to add items to the Options Menu setHasOptionsMenu(true); // update the actionbar to show the up carat/affordance getActivity().getActionBar().setDisplayHomeAsUpEnabled(true); } 

然后,在onOptionsItemSelected只要<按下它,它onBackPressed()从activity中调用onBackPressed()以在层次结构中向上移动一层,并显示导航抽屉图像:

 @Override public boolean onOptionsItemSelected(MenuItem item) { // Get item selected and deal with it switch (item.getItemId()) { case android.R.id.home: //called when the up affordance/carat in actionbar is pressed getActivity().onBackPressed(); return true; … } 

您已经写道,为了实现较低级别的片段,您将replace现有的片段,而不是在新活动中实现较低级别的片段。

我认为你将不得不手动实现后端function:当用户按下你有代码popup堆栈(例如在Activity::onBackPressed覆盖)。 所以,无论你在哪里做,都可以反转setDrawerIndicatorEnabled

这很容易,如1-2-3。

如果你想实现:

1) 抽屉指示器 – 当没有碎片在返回堆栈或抽屉打开时

2) 箭头 – 当一些碎片在后堆栈

 private FragmentManager.OnBackStackChangedListener mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { syncActionBarArrowState(); } }; @Override protected void onCreate(Bundle savedInstanceState) { getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); mDrawerToggle = new ActionBarDrawerToggle( this, mDrawerLayout, R.drawable.ic_navigation_drawer, 0, 0 ) { public void onDrawerClosed(View view) { syncActionBarArrowState(); } public void onDrawerOpened(View drawerView) { mDrawerToggle.setDrawerIndicatorEnabled(true); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener); } @Override protected void onDestroy() { getSupportFragmentManager().removeOnBackStackChangedListener(mOnBackStackChangedListener); super.onDestroy(); } private void syncActionBarArrowState() { int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount(); mDrawerToggle.setDrawerIndicatorEnabled(backStackEntryCount == 0); } 

3)两个指标都要根据自己的形态来行事

 @Override public boolean onOptionsItemSelected(MenuItem item) { if (mDrawerToggle.isDrawerIndicatorEnabled() && mDrawerToggle.onOptionsItemSelected(item)) { return true; } else if (item.getItemId() == android.R.id.home && getSupportFragmentManager().popBackStackImmediate()) { return true; } else { return super.onOptionsItemSelected(item); } } 

PS请参阅在Android Developers上创build导航抽屉,了解有关3线指示器行为的其他提示。

我用了下面的东西:

 getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { if(getSupportFragmentManager().getBackStackEntryCount() > 0){ mDrawerToggle.setDrawerIndicatorEnabled(false); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } else { getSupportActionBar().setDisplayHomeAsUpEnabled(false); mDrawerToggle.setDrawerIndicatorEnabled(true); } } }); 

如果您的向上操作栏button不起作用,请不要忘记添加侦听器:

 // Navigation back icon listener mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); 

用homebutton实现抽屉导航时遇到了一些麻烦,除了动作button之外,所有的东西都可以工作。

尝试处理MainActivity中的Home项目选项,具体取决于DrawerToggle的状态。 这样你就不必为每个片段添加相同的代码。

 @Override public boolean onOptionsItemSelected(MenuItem item) { // Only handle with DrawerToggle if the drawer indicator is enabled. if (mDrawerToggle.isDrawerIndicatorEnabled() && mDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle action buttons switch (item.getItemId()) { // Handle home button in non-drawer mode case android.R.id.home: onBackPressed(); return true; default: return super.onOptionsItemSelected(item); } } 

跟进

@dzeikei提供的解决scheme是整洁的,但是当使用碎片时,它可以被扩展,以在后台空置时自动处理抽屉指示器的设置。

 @Override public boolean onOptionsItemSelected(MenuItem item) { // Only handle with DrawerToggle if the drawer indicator is enabled. if (mDrawerToggle.isDrawerIndicatorEnabled() && mDrawerToggle.onOptionsItemSelected(item)) { return true; } // Handle action buttons switch (item.getItemId()) { // Handle home button in non-drawer mode case android.R.id.home: // Use getSupportFragmentManager() to support older devices FragmentManager fragmentManager = getFragmentManager(); fragmentManager.popBackStack(); // Make sure transactions are finished before reading backstack count fragmentManager.executePendingTransactions(); if (fragmentManager.getBackStackEntryCount() < 1){ mDrawerToggle.setDrawerIndicatorEnabled(true); } return true; default: return super.onOptionsItemSelected(item); } } 

编辑

对于@JJD的问题。

片段被保存/pipe理在一个活动中。 上面的代码在该活动中被写入一次,但只处理onOptionsItemSelected的上一个字符。

在我的一个应用程序中,我还需要处理后退button被按下时的行为。 这可以通过重写onBackPressed来处理。

 @Override public void onBackPressed() { // Use getSupportFragmentManager() to support older devices FragmentManager fragmentManager = getFragmentManager(); fragmentManager.executePendingTransactions(); if (fragmentManager.getBackStackEntryCount() < 1){ super.onBackPressed(); } else { fragmentManager.executePendingTransactions(); fragmentManager.popBackStack(); fragmentManager.executePendingTransactions(); if (fragmentManager.getBackStackEntryCount() < 1){ mDrawerToggle.setDrawerIndicatorEnabled(true); } } }; 

注意onOptionsItemSelectedonBackPressed之间的代码重复,可以通过在两个地方创build一个方法并调用该方法来避免。

另外请注意,我再多加两次executePendingTransactions ,在我的情况下是必需的,否则我有时会有一些奇怪的行为。

我为托pipe活动创build了一个界面来更新汉堡包菜单的视图状态。 对于最高级别的片段,我将切换设置为true ,对于我要显示的片段<箭头,我将切换设置为false

 public class SomeFragment extends Fragment { public interface OnFragmentInteractionListener { public void showDrawerToggle(boolean showDrawerToggle); } private OnFragmentInteractionListener mListener; @Override public void onAttach(Activity activity) { super.onAttach(activity); try { this.mListener = (OnFragmentInteractionListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onResume() { super.onResume(); mListener.showDrawerToggle(false); } } 

然后在我的活动…

 public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener { private ActionBarDrawerToggle mDrawerToggle; public void showDrawerToggle(boolean showDrawerIndicator) { mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator); } } 

这个答案正在工作,但有一个小问题。 没有明确调用getSupportActionBar().setDisplayHomeAsUpEnabled(false) ,即使在后台堆栈中没有项目时,也会导致抽屉图标被隐藏,所以更改setActionBarArrowDependingOnFragmentsBackStack()方法对我很有用。

 private void setActionBarArrowDependingOnFragmentsBackStack() { int backStackEntryCount = getSupportFragmentManager() .getBackStackEntryCount(); // If there are no items in the back stack if (backStackEntryCount == 0) { // Please make sure that UP CARAT is Hidden otherwise Drawer icon // wont display getSupportActionBar().setDisplayHomeAsUpEnabled(false); // Display the Drawer Icon mDrawerToggle.setDrawerIndicatorEnabled(true); } else { // Show the Up carat getSupportActionBar().setDisplayHomeAsUpEnabled(true); // Hide the Drawer Icon mDrawerToggle.setDrawerIndicatorEnabled(false); } } 

逻辑清晰。 如果碎片堆栈清除,则显示回退button。 如果片段堆栈不清晰,则显示素材汉堡后退animation。

 getSupportFragmentManager().addOnBackStackChangedListener( new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { syncActionBarArrowState(); } } ); private void syncActionBarArrowState() { int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount(); mNavigationDrawerFragment.setDrawerIndicatorEnabled(backStackEntryCount == 0); } //add these in Your NavigationDrawer fragment class public void setDrawerIndicatorEnabled(boolean flag){ ActionBar actionBar = getActionBar(); if (!flag) { mDrawerToggle.setDrawerIndicatorEnabled(false); actionBar.setDisplayHomeAsUpEnabled(true); mDrawerToggle.setHomeAsUpIndicator(getColoredArrow()); } else { mDrawerToggle.setDrawerIndicatorEnabled(true); } mDrawerToggle.syncState(); getActivity().supportInvalidateOptionsMenu(); } //download back button from this(https://www.google.com/design/icons/) website and add to your project private Drawable getColoredArrow() { Drawable arrowDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_arrow_back_black_24dp); Drawable wrapped = DrawableCompat.wrap(arrowDrawable); if (arrowDrawable != null && wrapped != null) { // This should avoid tinting all the arrows arrowDrawable.mutate(); DrawableCompat.setTint(wrapped, Color.GRAY); } return wrapped; } 

如果您查看GMAIL应用程序并来此searchcarret /的可爱图标..

我会请你这样做,上面的答案都不清楚。 我能够修改接受的答案。

  • NavigationDrawer – > Listview包含子片段。


  • 亚片段将如此列出

  • firstFragment == position 0 —>这将有subfragments – > fragment

  • secondFragment
  • 第三个片段等等。

在firstFragment中你有其他的片段。

在DrawerActivity上调用它

 getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { if (getFragmentManager().getBackStackEntryCount() > 0) { mDrawerToggle.setDrawerIndicatorEnabled(false); } else { mDrawerToggle.setDrawerIndicatorEnabled(true); } } }); 

并在片段

  setHasOptionsMenu(true); @Override public boolean onOptionsItemSelected(MenuItem item) { // Get item selected and deal with it switch (item.getItemId()) { case android.R.id.home: //called when the up affordance/carat in actionbar is pressed activity.onBackPressed(); return true; } return false; } 

在OnBackPressed Drawer活动方法上,将抽屉切换为true以再次启用导航列表图标。

谢谢,Pusp

你可以看看这个小例子! https://github.com/oskarko/NavDrawerExample

国际海事组织,使用onNavigateUp()(如图所示)在riwnodennyk的或汤姆的解决scheme是更清洁,似乎更好地工作。 只需用下面的代码replaceonOptionsItemSelected代码:

 @Override public boolean onSupportNavigateUp() { if (getSupportFragmentManager().getBackStackEntryCount() > 0) { // handle up navigation return true; } else { return super.onSupportNavigateUp(); } }