工具栏 - 从抽屉切换到后退按钮只有一个 Activity
Toolbar - Switching from drawer to back button with only one Activity
我一直在寻找如何将抽屉 open/close 图标(从汉堡包变为箭头)更改为简单的后退箭头。我的应用程序目前只有一个 Activity 在几个片段之间切换。有一次,我想在一个主要片段(即,抽屉中的片段之一)之间过渡到按层次结构位于前一个片段下方的片段(即,“添加新”片段)。在这个新片段中,我想让工具栏显示后退按钮而不是抽屉按钮。
我已经环顾四周并尝试了很长一段时间的不同解决方案。以下是最值得注意的:
- Change drawer icon back to back arrow - 我成功地移除了抽屉图标,但是原地没有……什么都没有。没有向上插入符号,没有后退按钮,没有图标。我怀疑这是因为我的 Activity 没有父级,但除了廉价的解决方法(创建另一个 Activity 作为启动主 Activity 的父级),我在不知所措。
- Switching between Android Navigation Drawer image and Up caret when using fragments - 与上面类似,但有更多细节。最终,图标仍然没有变成后退按钮。
- Android lollipop toolbar switch between open/close drawer and back button - 我觉得这很难理解,但最终可以点击抽屉图标并且什么都不做(尽管我相信我知道如何让它充当后按)。但是,图标没有改变。
此刻,我正在考虑创建一个我隐藏和显示的自定义图标(以及 hide/show 本机抽屉图标)的漫长而艰巨的方法。但是,有没有更好的方法在抽屉和后退按钮之间切换?
作为一个侧面但相关的问题,我一直在查看 Material 设计文档,一些示例在左上角有一个 X。这与实现抽屉与 back/up 按钮相比有何不同?
谢谢~
编辑:
我知道如何替换图标,但如何获取点击事件?
到目前为止,这是我最好的领先:
- Cannot catch toolbar home button click event
我现在尝试过的:
- 必要时禁用 DrawerToggle(即
mDrawerToggle.setDrawerIndicatorEnabled(useDrawer);
)
- 在我的 NavigationDrawerFragment、我的 Activity 以及我当前正在测试的 DialogFragment 中的 onOptionsItemSelected 中添加了日志,如果
item.getItemId() == android.R.id.home
为真,则 运行。 None 这些日志语句关闭
为了更好的上下文,我现在有一个全屏片段,它向菜单添加了一个“保存”按钮并将抽屉图标更改为“X”。 fragment可以获取保存菜单事件,但点击X时连Activity和Drawer都获取不到
编辑2:
根据要求,这是一些代码。请注意,这全部来自 this Github repo,我正在积极处理(请注意,我在快速测试中在这里或那里有一些无用的功能)。
@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);
}
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);
}
@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;
}
解决方案:
在 natario 下面的回答的帮助下,这是我最终得出的最终解决方案:
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();
}
});
}
这可能不是您想听到的,但即使从概念的角度来看,我也会选择新的 activity 而不是片段。
你的主要 activity 严格地 linked 到抽屉,所以加载一个新片段而不访问抽屉对我来说没有意义(但如果你愿意等待其他答案也这样觉得)。一个新的 activity 可以解决这两个问题,因为它没有抽屉并且可以是主抽屉的子项。
你的附带问题看起来也很正确。 "Add New" activity 可以很好地适应指南中的 "full-screen dialog" 视觉模式。参见:
http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs
此模式有一个 "save"、右上角的肯定按钮和一个 X。从概念上讲,X 按钮是 cancel/abort 一个进程,而不是向上导航一些后台堆栈。这意味着你在不让任何行动发生的情况下驳回某些事情。这很适合你想做的事情。
从设计的角度来看,它很容易由一个新的 Activity
制成,可以保持在其他人之上。此外,如果片段的要点基本上是能够在平板电脑和更大的屏幕上同时表示两个或更多 - 再一次 - 我不会对左边的旧片段和左边的 "Add New" 片段感到满意对。
相反 - 在平板电脑上 - 我会按照指南的建议使用浮动对话框。
http://www.google.com/design/spec/components/dialogs.html#dialogs-confirmation-dialogs
所以全屏 activity 手机有 X 按钮,平板电脑有浮动对话框(按钮在底部)。对我来说,这是最符合准则的方法。
我建议阅读全文 link。关于<-和X的区别,
The X differs from an Up arrow, which is used when the view’s state is constantly being saved or when apps have draft or autosave capabilities. For example, an Up arrow is used in Settings because all changes are committed immediately.
还有
Touching the X in this Settings example will discard all changes. Changes will be saved only upon touching Save.
它甚至应该适用于最新的 API 24.
在您的 activity 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);
}
}
});
将此代码放入您的 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);
}
});
}
}
});
@matusalem 的回答很有效。我只是想补充一点——小心点,因为抽屉也可以通过从屏幕左侧滑入来打开。对于某些人来说,这可能是需要的,但对我来说,我禁用了抽屉,因为它在除我的主要片段之外的任何片段中都没有意义。滑动在这里很容易被禁用 -
Navigation drawer - disable swipe
这可能属于对答案的评论,但我没有足够的声誉。抱歉。
我在更改片段时在同一 activity 内的汉堡菜单和后退箭头之间切换时遇到了同样的问题。这是我的工作解决方案,希望对某人有所帮助。
您的 activity 中的监听器:
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);
...
...
你感兴趣的部分评论(Class返回的是我的部分class,可以设置为无效):
/**
* 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;
}
注意:调用方法的顺序很重要!如果能像这样把它写成两行会更好但是不会工作(至少对我来说):
toggle.setDrawerIndicatorEnabled(!enableBackDrawerIcon);
getSupportActionBar().setDisplayHomeAsUpEnabled(enableBackDrawerIcon);
如果您对方法调用顺序混乱的原因感兴趣,请查看这些方法的实现。
//This if block makes the menu back button to respond to clicks
//The onOptionsItemSelected fun for whatever reason was not capturing back menu clicks
if (toolbar != null) {
/* toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
toggle.syncState()
drawer_layout.setDrawerListener(toggle)*/
supportFragmentManager.addOnBackStackChangedListener(object : FragmentManager.OnBackStackChangedListener {
override fun onBackStackChanged() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportActionBar?.setDisplayHomeAsUpEnabled(true) // show back button
toolbar.setNavigationOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
onBackPressed()
}
})
} else {
//show hamburger
supportActionBar?.setDisplayHomeAsUpEnabled(false)
toggle.syncState()
toolbar.setNavigationOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
drawer_layout.openDrawer(GravityCompat.START)
}
})
}
}
})
}
You need to comment out "toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
toggle.syncState()
drawer_layout.setDrawerListener(toggle)" (4-7 lines) if you are using the auto generated Navigation layout in Android Studio, else the behavior of the back menu button will be erratic. That is what i did and it worked perfectly for me. Hope this helps someone
我一直在寻找如何将抽屉 open/close 图标(从汉堡包变为箭头)更改为简单的后退箭头。我的应用程序目前只有一个 Activity 在几个片段之间切换。有一次,我想在一个主要片段(即,抽屉中的片段之一)之间过渡到按层次结构位于前一个片段下方的片段(即,“添加新”片段)。在这个新片段中,我想让工具栏显示后退按钮而不是抽屉按钮。
我已经环顾四周并尝试了很长一段时间的不同解决方案。以下是最值得注意的:
- Change drawer icon back to back arrow - 我成功地移除了抽屉图标,但是原地没有……什么都没有。没有向上插入符号,没有后退按钮,没有图标。我怀疑这是因为我的 Activity 没有父级,但除了廉价的解决方法(创建另一个 Activity 作为启动主 Activity 的父级),我在不知所措。
- Switching between Android Navigation Drawer image and Up caret when using fragments - 与上面类似,但有更多细节。最终,图标仍然没有变成后退按钮。
- Android lollipop toolbar switch between open/close drawer and back button - 我觉得这很难理解,但最终可以点击抽屉图标并且什么都不做(尽管我相信我知道如何让它充当后按)。但是,图标没有改变。
此刻,我正在考虑创建一个我隐藏和显示的自定义图标(以及 hide/show 本机抽屉图标)的漫长而艰巨的方法。但是,有没有更好的方法在抽屉和后退按钮之间切换?
作为一个侧面但相关的问题,我一直在查看 Material 设计文档,一些示例在左上角有一个 X。这与实现抽屉与 back/up 按钮相比有何不同?
谢谢~
编辑:
我知道如何替换图标,但如何获取点击事件?
到目前为止,这是我最好的领先:
- Cannot catch toolbar home button click event
我现在尝试过的:
- 必要时禁用 DrawerToggle(即
mDrawerToggle.setDrawerIndicatorEnabled(useDrawer);
) - 在我的 NavigationDrawerFragment、我的 Activity 以及我当前正在测试的 DialogFragment 中的 onOptionsItemSelected 中添加了日志,如果
item.getItemId() == android.R.id.home
为真,则 运行。 None 这些日志语句关闭
为了更好的上下文,我现在有一个全屏片段,它向菜单添加了一个“保存”按钮并将抽屉图标更改为“X”。 fragment可以获取保存菜单事件,但点击X时连Activity和Drawer都获取不到
编辑2:
根据要求,这是一些代码。请注意,这全部来自 this Github repo,我正在积极处理(请注意,我在快速测试中在这里或那里有一些无用的功能)。
@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);
}
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);
}
@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;
}
解决方案:
在 natario 下面的回答的帮助下,这是我最终得出的最终解决方案:
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();
}
});
}
这可能不是您想听到的,但即使从概念的角度来看,我也会选择新的 activity 而不是片段。
你的主要 activity 严格地 linked 到抽屉,所以加载一个新片段而不访问抽屉对我来说没有意义(但如果你愿意等待其他答案也这样觉得)。一个新的 activity 可以解决这两个问题,因为它没有抽屉并且可以是主抽屉的子项。
你的附带问题看起来也很正确。 "Add New" activity 可以很好地适应指南中的 "full-screen dialog" 视觉模式。参见:
http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs
此模式有一个 "save"、右上角的肯定按钮和一个 X。从概念上讲,X 按钮是 cancel/abort 一个进程,而不是向上导航一些后台堆栈。这意味着你在不让任何行动发生的情况下驳回某些事情。这很适合你想做的事情。
从设计的角度来看,它很容易由一个新的 Activity
制成,可以保持在其他人之上。此外,如果片段的要点基本上是能够在平板电脑和更大的屏幕上同时表示两个或更多 - 再一次 - 我不会对左边的旧片段和左边的 "Add New" 片段感到满意对。
相反 - 在平板电脑上 - 我会按照指南的建议使用浮动对话框。
http://www.google.com/design/spec/components/dialogs.html#dialogs-confirmation-dialogs
所以全屏 activity 手机有 X 按钮,平板电脑有浮动对话框(按钮在底部)。对我来说,这是最符合准则的方法。
我建议阅读全文 link。关于<-和X的区别,
The X differs from an Up arrow, which is used when the view’s state is constantly being saved or when apps have draft or autosave capabilities. For example, an Up arrow is used in Settings because all changes are committed immediately.
还有
Touching the X in this Settings example will discard all changes. Changes will be saved only upon touching Save.
它甚至应该适用于最新的 API 24.
在您的 activity 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);
}
}
});
将此代码放入您的 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);
}
});
}
}
});
@matusalem 的回答很有效。我只是想补充一点——小心点,因为抽屉也可以通过从屏幕左侧滑入来打开。对于某些人来说,这可能是需要的,但对我来说,我禁用了抽屉,因为它在除我的主要片段之外的任何片段中都没有意义。滑动在这里很容易被禁用 - Navigation drawer - disable swipe
这可能属于对答案的评论,但我没有足够的声誉。抱歉。
我在更改片段时在同一 activity 内的汉堡菜单和后退箭头之间切换时遇到了同样的问题。这是我的工作解决方案,希望对某人有所帮助。
您的 activity 中的监听器:
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);
...
...
你感兴趣的部分评论(Class返回的是我的部分class,可以设置为无效):
/**
* 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;
}
注意:调用方法的顺序很重要!如果能像这样把它写成两行会更好但是不会工作(至少对我来说):
toggle.setDrawerIndicatorEnabled(!enableBackDrawerIcon);
getSupportActionBar().setDisplayHomeAsUpEnabled(enableBackDrawerIcon);
如果您对方法调用顺序混乱的原因感兴趣,请查看这些方法的实现。
//This if block makes the menu back button to respond to clicks
//The onOptionsItemSelected fun for whatever reason was not capturing back menu clicks
if (toolbar != null) {
/* toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
toggle.syncState()
drawer_layout.setDrawerListener(toggle)*/
supportFragmentManager.addOnBackStackChangedListener(object : FragmentManager.OnBackStackChangedListener {
override fun onBackStackChanged() {
if (supportFragmentManager.backStackEntryCount > 0) {
supportActionBar?.setDisplayHomeAsUpEnabled(true) // show back button
toolbar.setNavigationOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
onBackPressed()
}
})
} else {
//show hamburger
supportActionBar?.setDisplayHomeAsUpEnabled(false)
toggle.syncState()
toolbar.setNavigationOnClickListener(object : View.OnClickListener {
override fun onClick(v: View) {
drawer_layout.openDrawer(GravityCompat.START)
}
})
}
}
})
}
You need to comment out "toggle = ActionBarDrawerToggle( this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) toggle.syncState() drawer_layout.setDrawerListener(toggle)" (4-7 lines) if you are using the auto generated Navigation layout in Android Studio, else the behavior of the back menu button will be erratic. That is what i did and it worked perfectly for me. Hope this helps someone