我已经搜索了一段时间,了解如何在抽屉打开/关闭图标(从汉堡到箭头)到简单的后退箭头之间切换。我的应用程序目前只有一个在几个片段之间切换的"活动"。在某一点上,我想在一个主要片段(即抽屉中的一个片段)到一个在层次上位于前一个片段下的片段(即"添加新"片段)之间转换。在这个新片段中,我希望工具栏显示后退按钮,而不是抽屉按钮。
很长一段时间以来,我一直在四处寻找并尝试不同的解决方案。以下是最值得注意的:
- 更改抽屉图标前后箭头-我成功地删除了抽屉图标,但在适当的位置有。。。。没有什么没有向上插入符号,没有后退按钮,没有图标。我怀疑这是因为我的"活动"没有父级,但除了一个廉价的变通方法(创建另一个充当启动主"活动"的父级的"活动)之外,我不知道该做什么
- 当使用片段时,在Android导航抽屉图像和向上插入符号之间切换-类似于上面的内容,但有更多细节。最终,图标仍然不会变成后退按钮
- 安卓棒棒糖工具栏在打开/关闭抽屉和后退按钮之间切换-我发现这很难理解,但最终抽屉图标可以被点击,什么也不做(尽管我相信我知道如何让它充当后退按钮)。但是,图标不会改变
目前,我正在考虑一种漫长而艰巨的方法来创建一个我隐藏和显示的自定义图标(以及隐藏/显示本地抽屉图标)。然而,有没有更好的方法可以在抽屉和背面按钮之间切换?
作为一个侧面但相关的问题,我一直在看材料设计文档,一些例子的左上角有一个X。这与实现抽屉与备份/备份按钮有什么不同?
谢谢~
编辑:
我可以弄清楚如何替换图标,但如何获得点击事件?
到目前为止,这是我最好的线索:
- 无法捕获工具栏主页按钮单击事件
我现在尝试过的:
- 必要时禁用抽屉切换(即
mDrawerToggle.setDrawerIndicatorEnabled(useDrawer);
) - 在我的NavigationDrawerFragment、我的活动中的onOptionsItemSelected中添加了日志,以及我当前正在测试的在
item.getItemId() == android.R.id.home
为true时运行的DialogFragment。这些日志语句都没有出错
为了更好的上下文,我现在有一个全屏片段,它添加了一个";保存";按钮切换到菜单,并将抽屉图标更改为"0";X〃;。片段可以获得保存菜单事件,但当点击X时,即使是活动和抽屉也无法获得。
第2版:
根据要求,这里有一些代码。请注意,这一切都来自我正在积极研究的Github repo(请注意,我在快速测试中有一些无用的功能)。
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);
}
导航抽屉碎片:
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;
}
解决方案:
这是我最终得到的最终解决方案,在纳塔里奥下面的回答的帮助下:
导航抽屉碎片:
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
的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);
}
}
});
这可能不是你想听到的,但即使从概念的角度来看,我也会选择一个新的活动,而不是一个片段。
你的主要活动与抽屉严格相关,所以在没有任何抽屉访问权限的情况下加载新片段对我来说毫无意义(但如果你这么认为,请随时等待其他答案)。一个新的活动将解决这两个问题,因为它将没有抽屉,并且可能是主要抽屉的子项。
你的旁侧问题看起来也很正确。"添加新内容"活动可以很好地适应指南中的"全屏对话框"视觉模式。参见:
http://www.google.com/design/spec/components/dialogs.html#dialogs-全屏幕对话框
这个模式在右上角有一个"保存"的正按钮和一个X。从概念上讲,X按钮是取消/中止一个过程,而不是导航到一些后台。这意味着你在不采取任何行动的情况下解雇了一些人。这很适合你想做的事情。
从设计的角度来看,它很容易由一个新的Activity
制造,它可以保持在其他产品之上。此外,如果碎片的意义基本上是能够在平板电脑和更大的屏幕上同时表示两个或多个碎片,那么我不会对左边的旧碎片和右边的"添加新"碎片感到高兴。
相反,在平板电脑上,我会按照指导方针的建议,选择浮动对话框。
http://www.google.com/design/spec/components/dialogs.html#dialogs-确认对话框
因此,手机使用X按钮进行全屏活动,平板电脑使用浮动对话框(底部有按钮)。对我来说,这是最符合指导方针的连贯方法。
我建议阅读整个链接。关于<-和X,
X与向上箭头不同,向上箭头用于不断保存视图状态或应用程序具有草稿或自动保存功能时。例如,在"设置"中使用向上箭头,因为所有更改都会立即提交。
还有
在此设置示例中触摸X将放弃所有更改。只有在触摸保存时,更改才会被保存。
@matusalem的答案非常有效。我只想补充一点——小心,因为抽屉也可以从屏幕左侧滑动打开。对一些人来说,这可能是想要的,但对我来说,我禁用了抽屉,因为它在除了我的主片段之外的任何片段中都没有意义。此处很容易禁用滑动-导航抽屉-禁用滑动
这可能属于对答案的评论,但我没有足够的声誉。我很抱歉。
在更换碎片时,我在相同活动内的汉堡菜单和后退箭头之间切换时遇到了同样的问题。这是我的工作解决方案,希望对某人有所帮助。
活动中的监听器:
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;
}
注意:被调用方法的顺序很重要!如果能像这样写两行就更好了,但不起作用(至少对我来说):
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)
}
})
}
}
})
}
您需要注释掉"toggle=ActionBarDrawerToggle(这个,drawer_layout,工具栏,R.string.navigation_drawer_open,R.strin.navigation_dower_close)toggle.syncState()drawer_layout.setDrawerListener(toggle)"(4-7行)如果你在Android Studio中使用自动生成的导航布局,否则返回菜单按钮的行为将不稳定。这就是我所做的,它对我来说非常有效。希望这能帮助