工具栏 – 只有一个活动从抽屉切换到后退button

我一直在寻找如何改变抽屉打开/closures图标(从汉堡到箭头)到简单的后退箭头。 我的应用程序目前只有一个Activity在几个片段之间切换。 在某一点上,我想要在一个主要的片段(即抽屉中的一个片段)和一个分层的片段(即“Add New”片段)之间转换。 在这个新的片段中,我想让工具栏显示后退button而不是抽屉button。

我一直在环顾四周,尝试不同的解决scheme很长一段时间。 这是最值得注意的:

  • 改变抽屉图标背对背箭头 – 我成功地删除了抽屉图标,但是在那里没有….没有。 没有脱字符号,没有后退button,没有图标。 我怀疑这是因为我的活动没有父母,但除了一个廉价的工作(创build另一个活动,作为启动主要活动的父母),我迷失了该怎么做。
  • 在使用片段时,在Android Navigation Drawer图像和Up插入符之间切换 – 与上面类似,但有更多的细节。 最终,图标仍然不会变成后退button。
  • Android棒棒糖工具栏在打开/closures抽屉和后退button之间切换 – 我发现这很难遵循,但最终抽屉图标可以被挖掘,什么都不做(尽pipe我相信我知道如何使它作为后退button)。 但是,图标不会更改。

目前,我正在考虑创build一个自定义图标,并隐藏和显示(并隐藏/显示原始抽屉图标)的一种漫长而艰巨的方法。 但是,是否有更好的方式来切换抽屉和后退button?

作为一个侧面相关的问题,我一直在看材料devise文档,一些例子在左上angular有一个X. 与实现抽屉和后退/上拉button有什么不同?

谢谢〜

编辑:

我可以弄清楚如何replace图标,但是如何获得点击事件呢?

到目前为止,这是我最好的领导:

  • 无法捕捉工具栏主页button单击事件

我现在试过的:

  • 必要时禁用DrawerToggle(即, mDrawerToggle.setDrawerIndicatorEnabled(useDrawer);
  • 在我的NavigationDrawerFragment中添加了onOptionsItemSelected日志,我的Activity以及DialogFragment我正在testing哪些运行如果item.getItemId() == android.R.id.home为true。 这些日志语句都没有closures

为了更好的上下文,我现在有一个全屏幕的片段,在菜单上添加一个“保存”button,并将抽屉图标更改为“X”。 片段可以得到保存菜单事件,但是当轻击X时甚至不能得到活动和抽屉。

EDIT2:

根据要求,这是一些代码。 请注意,这是从这个Github回购 ,我正在积极的工作(注意,我有一些无用的function,这里或那里从快速testing)。

ActivityMain

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Add the toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); if (mToolbar != null) { setSupportActionBar(mToolbar); } // Initialize the drawer mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer); // Set up the drawer mNavigationDrawerFragment.setUp( R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout), mToolbar); // TODO: Check if this helps to catch the main toolbar button click getSupportActionBar().setDisplayShowHomeEnabled(true); // Get the titles for the Toolbar mTitles = getResources().getStringArray(R.array.drawer_items); mDrawerPosition = -1; if (savedInstanceState == null) { // If there was no saved position, then the default, starting position should be used forceChangeItemSelected(0); } else { // Otherwise, get the saved position from the bundle int position = savedInstanceState.getInt(KEY_DRAWERPOS); mNavigationDrawerFragment.setSelectedItem(position); // Title needs to be re-set getSupportActionBar().setTitle(mTitles[position]); } // If I include the below bit, then the DrawerToggle doesn't function // I don't know how to switch it back and forth mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Log.d(LOG_TAG, "Navigation was clicked"); } }); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. Log.d(LOG_TAG, "Activity responding to menu click..."); if(item.getItemId() == android.R.id.home) Log.d(LOG_TAG, "Activity got it...."); // If the fragment is supposed to handle things, then let it if(mIsFragmentHandlingMenus) return false; int id = item.getItemId(); if(id == R.id.save) { // This isn't implemented! If chosen, then there's a bug! Log.e(LOG_TAG, "onOptionsItemSelected: Save was selected!"); } return super.onOptionsItemSelected(item); } @Override public void fragmentHandlingMenus(boolean isFragmentHandlingMenus) { // Simply store the setting mIsFragmentHandlingMenus = isFragmentHandlingMenus; // Toggle the drawer as necessary mNavigationDrawerFragment.toggleDrawerUse(!isFragmentHandlingMenus); } 

NavigationDrawerFragment

 public void toggleDrawerUse(boolean useDrawer) { // Enable/Disable the icon being used by the drawer mDrawerToggle.setDrawerIndicatorEnabled(useDrawer); // TODO: Enable/Disable the drawer even being able to open/close } @Override public boolean onOptionsItemSelected(MenuItem item) { Log.d(LOGTAG, "Drawer responding to menu click..."); if(item.getItemId() == android.R.id.home) Log.d(LOGTAG, "Drawer got it...."); if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } 

GoalAdderFragment

 @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // Allow this fragment to handle toolbar menu items setHasOptionsMenu(true); // Set up the toolbar ((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true); ((ActionBarActivity) getActivity()).getSupportActionBar().setHomeAsUpIndicator(android.R.drawable.ic_menu_close_clear_cancel); ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(getResources().getString(R.string.title_addgoal)); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // Cache the Activity as the frag handler if necessary if(mFragHandler == null) mFragHandler = (TransactionHandler.FragmentTransactionHandler) getActivity(); // Tell the Activity to let fragments handle the menu events mFragHandler.fragmentHandlingMenus(true); } @Override public void onDetach() { super.onDetach(); // Tell the Activity that it can now handle menu events once again mFragHandler.fragmentHandlingMenus(false); } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.save_menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { Log.d(LOGTAG, "Item id: " + item.getItemId() + " | Save id: " + R.id.save); Toast.makeText(getActivity(), "Fragment activated!", Toast.LENGTH_SHORT).show(); switch (item.getItemId()) { case R.id.save: return true; case android.R.id.home: return true; default: break; } return false; } 

解:

这是我最终解决scheme,在下面接受的答案的帮助下:

NavigationDrawerFragment

 private View.OnClickListener mOriginalListener; public void setUp(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) { /* Rest of setting up code */ // Save the default listener after setting everything else up mOriginalListener = mDrawerToggle.getToolbarNavigationClickListener(); } // Tells the toolbar+drawer to switch to the up button or switch back to the normal drawer public void toggleDrawerUse(boolean useDrawer) { // Enable/Disable the icon being used by the drawer mDrawerToggle.setDrawerIndicatorEnabled(useDrawer); // Switch between the listeners as necessary if(useDrawer) mDrawerToggle.setToolbarNavigationClickListener(mOriginalListener); else mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getActivity(), "Custom listener", Toast.LENGTH_SHORT).show(); } }); } 

这可能不是你想听到的,但是即使从概念的angular度来看,我也会去做一个新的活动,而不是一个片段。

你的主要活动是与抽屉紧密相连的,所以加载一个没有任何访问抽屉的新片段对我来说没有任何意义(但如果你这么想的话,请随时等待其他答案)。 一个新的活动将解决这两个问题,因为它不会有抽屉,可能是主要的孩子。

你的侧面问题也看上去也是现货。 “添加新的”活动可以很好地适应指南中的“全屏对话”视觉模式。 看到:

http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs

这种模式有一个“保存”,右上angular的正面button和一个X.从概念上讲,Xbutton是取消/中止一个过程,而不是导航一些后台。 这意味着你在不采取任何行动的情况下解雇某人。 这适合你想要做的事情。

从devise的angular度来看,它很容易通过一个新的Activity ,可以保持在别人之上。 此外,如果碎片的点基本上能够在平板电脑和更大的屏幕上同时performance两个或更多 – 我再也不会对我左侧的旧片段和右侧的“添加新片段”感到满意。

相反 – 在平板电脑上 – 我会按照指导方针的build议进行浮动对话。

http://www.google.com/design/spec/components/dialogs.html#dialogs-confirmation-dialogs

所以,全屏幕的活动包括手机的Xbutton和平板电脑的浮动对话框(底部有button)。 对我而言,这是最符合指导原则的方法。


我build议阅读整个链接。 在< – 和X之间的区别,

X不同于向上箭头,当视图的状态不断被保存或应用程序具有草稿或自动保存function时使用。 例如,设置中使用向上箭头,因为所有更改都立即提交。

并且

在此设置示例中触摸X将放弃所有更改。 仅在触摸保存时才会保存更改。

把这段代码放到Activity onCreate()中。 适合我。 即使使用compileSdk 23和更高。

  drawer = (DrawerLayout) findViewById(R.id.drawer_layout); final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); if(toolbar != null) { toggle = new ActionBarDrawerToggle( this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); toggle.syncState(); drawer.setDrawerListener(toggle); getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { if (getSupportFragmentManager().getBackStackEntryCount() > 0) { getSupportActionBar().setDisplayHomeAsUpEnabled(true); // show back button toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); } else { //show hamburger getSupportActionBar().setDisplayHomeAsUpEnabled(false); toggle.syncState(); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { drawer.openDrawer(GravityCompat.START); } }); } } }); 

即使是最新的API 24也应该可以工作。

在你的活动onCreate()这样做:

 final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); final DrawerLayout drawer = (DrawerLayout) view.findViewById(R.id.drawer_layout); setSupportActionBar(toolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); final View.OnClickListener originalToolbarListener = toggle.getToolbarNavigationClickListener(); getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() { @Override public void onBackStackChanged() { if (getSupportFragmentManager().getBackStackEntryCount() > 0) { toggle.setDrawerIndicatorEnabled(false); toggle.setToolbarNavigationClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getSupportFragmentManager().popBackStack(); } }); } else { toggle.setDrawerIndicatorEnabled(true); toggle.setToolbarNavigationClickListener(originalToolbarListener); } } }); 

@matusalem的答案很好。 我只是有一点点要添加它 – 要小心,因为抽屉也可以通过从屏幕左侧滑入打开。 对于某些人来说,这可能是需要的,但是对于我来说,我禁用了抽屉,因为它在任何片段中都没有意义,只是我的主要片段。 滑动很容易在这里禁用 – 导航抽屉 – 禁用滑动

这可能属于评论的答案,但我没有足够的声誉。 我很抱歉。

在更换碎片时,我在切换汉堡包菜单和后退箭头时遇到同样的问题。 这是我的工作解决scheme,希望对别人有帮助。

你的活动中的听众:

 private View.OnClickListener toolbarMenuListener = new View.OnClickListener() { @Override public void onClick(View v) { //will be called only if toggle.setDrawerIndicatorEnabled(false); ! Log.v(tag,"toggle onClick:"+v.getId()+" android.R.id.home:"+android.R.id.home); onBackPressed(); } }; 

代码onCreate()是这样的:

 ... ... setSupportActionBar(toolbar); toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); drawer.addDrawerListener(toggle); toggle.syncState(); //set listener so you know when back on arrow is pressed toggle.setToolbarNavigationClickListener(toolbarMenuListener); ... ... 

部分你有兴趣与评论(类返回是一些矿类,可以设置为无效):

 /** * Method to set up action bar drawer. * @param enableBackDrawerIcon set true if want to show drawer back arrow, * false to show hamburger menu. * @param title shown next to drawer icon */ public BaseMenusActivity drawerSetupToggle(boolean enableBackDrawerIcon, String title) { //NOTE: order of methods call is important! // If you change order order of setDrawerIndicatorEnabled and setDisplayHomeAsUpEnabled // method calls it won't work, weird bugs will happen (like no icon at all) if(enableBackDrawerIcon){ Log.v(tag,"show drawer back icon"); //hides hamburger menu and enables View.OnClickListener to be called toggle.setDrawerIndicatorEnabled(false); //show back arrow if(getSupportActionBar()!=null) getSupportActionBar().setDisplayHomeAsUpEnabled(true); } else { Log.v(tag,"show hamburger menu"); //hide back arrow if(getSupportActionBar()!=null) getSupportActionBar().setDisplayHomeAsUpEnabled(false); //shows hamburger menu and prevents View.OnClickListener to be called toggle.setDrawerIndicatorEnabled(true); } setTitle(title); return this; } 

:所谓的方法的顺序是重要的! 会更好,如果可以写在这样的两行,但不会工作 (至less对我来说):

 toggle.setDrawerIndicatorEnabled(!enableBackDrawerIcon); getSupportActionBar().setDisplayHomeAsUpEnabled(enableBackDrawerIcon); 

如果您对方法调用的顺序感兴趣,请查看这些方法的实现。