如何检测 DrawerLayout 开始打开?
Posted
技术标签:
【中文标题】如何检测 DrawerLayout 开始打开?【英文标题】:How to detect that the DrawerLayout started opening? 【发布时间】:2014-06-15 21:33:39 【问题描述】:所以当导航抽屉开始打开时,我想隐藏标签。我的代码在完成打开时将它们隐藏起来,但这不是我想要的。
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close
)
@Override
public void onDrawerClosed(View view)
invalidateOptionsMenu();
setActionBarMode(ActionBar.NAVIGATION_MODE_TABS);
@Override
public void onDrawerOpened(View drawerView)
invalidateOptionsMenu();
setActionBarMode(ActionBar.NAVIGATION_MODE_STANDARD);
;
mDrawerLayout.setDrawerListener(mDrawerToggle);
这是我尝试过的:
将onClickListener
设置为mDrawerLayout
。 onClick
永远不会被调用
将onTouchListener
设置为mDrawerLayout
。 onTouch
永远不会被调用
研究了ActionBarDrawerToggle
和DrawerLayout
类。找不到像 onDrawerStartedOpening
这样的东西。
【问题讨论】:
【参考方案1】:已弃用:查看其他答案以获得更合适的解决方案
有两种可能的方法来做到这一点:
-
使用
onDrawerSlide(View drawerView, float slideOffset)
回调
slideOffset
从 0 变为 1。1
表示完全打开,0
- 关闭。
一旦偏移量从0
更改为!0
- 这意味着它开始打开过程。比如:
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close
)
@Override
public void onDrawerSlide(View drawerView, float slideOffset)
if (slideOffset == 0
&& getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_STANDARD)
// drawer closed
getActionBar()
.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
invalidateOptionsMenu();
else if (slideOffset != 0
&& getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS)
// started opening
getActionBar()
.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
invalidateOptionsMenu();
super.onDrawerSlide(drawerView, slideOffset);
;
mDrawerLayout.setDrawerListener(mDrawerToggle);
-
使用
onDrawerStateChanged(int newState)
回调
您需要收听STATE_SETTLING
状态 - 每当抽屉开始移动(打开或关闭)时都会报告此状态。所以一旦你看到这个状态 - 检查抽屉现在是否打开并采取相应的行动:
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close
)
@Override
public void onDrawerStateChanged(int newState)
if (newState == DrawerLayout.STATE_SETTLING)
if (!isDrawerOpen())
// starts opening
getActionBar()
.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
else
// closing drawer
getActionBar()
.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
invalidateOptionsMenu();
;
mDrawerLayout.setDrawerListener(mDrawerToggle);
【讨论】:
第一种方法对我有用,但是有一个问题。当我试图滑动抽屉不是一直并将其释放到原来的位置时,标签没有恢复。原来对invalidateOptionsMenu();
的调用必须在setNavigationMode
之前。其他一切都很好。谢谢!
如何在我实现了导航抽屉的 MainActivity 中使用 onDrawerStateChanged 隐藏某些东西(例如:FAB 按钮)?
在使用onDrawerSlide
时收到大量已弃用的代码通知和“无法解决 isDrawerOpen()”错误... 有更新的答案吗?
@第一种方法超级棒
setDrawerListener
已弃用。更改为addDrawerListener
。 developer.android.com/reference/android/support/v4/widget/…【参考方案2】:
Pavel Dudka 目前接受的答案已被弃用。
请改用mDrawerLayout.addDrawerListener()
方法设置监听器。
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener()
@Override
public void onDrawerSlide(View drawerView, float slideOffset)
//Called when a drawer's position changes.
@Override
public void onDrawerOpened(View drawerView)
//Called when a drawer has settled in a completely open state.
//The drawer is interactive at this point.
// If you have 2 drawers (left and right) you can distinguish
// them by using id of the drawerView. int id = drawerView.getId();
// id will be your layout's id: for example R.id.left_drawer
@Override
public void onDrawerClosed(View drawerView)
// Called when a drawer has settled in a completely closed state.
@Override
public void onDrawerStateChanged(int newState)
// Called when the drawer motion state changes. The new state will be one of STATE_IDLE, STATE_DRAGGING or STATE_SETTLING.
);
完美运行。干杯!
【讨论】:
最新答案!谢谢!DrawerLayout.SimpmleDrawerListener
也可用,并为您不需要的东西提供无操作。【参考方案3】:
尝试重写 DrawerLayout.DrawerListener 的方法
@Override
public void onDrawerStateChanged(int newState)
if( newState == DrawerLayout.STATE_DRAGGING && isDrawerOpen() == false )
// this where Drawer start opening
【讨论】:
isDrawerOpen()
未定义。哪里来的?
@PrimožKralj 使用 DrawerLayout.isDrawerOpen(int drawerGravity)【参考方案4】:
最新解决方案:
正如其他人所建议的那样,当前答案已过时,建议使用mDrawerLayout.addDrawerListener()
。一个可行的解决方案是:
mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener()
@Override
public void onDrawerStateChanged(int newState)
if (newState == DrawerLayout.STATE_SETTLING && !mDrawerLayout.isDrawerOpen(GravityCompat.START))
// Drawer started opening
);
当然,将 GravityCompat.START
替换为任何标识您的抽屉(布局 ID 或其重力 ~ 位置)。
另外,如果您想检测抽屉何时开始关闭,您可以简单地执行以下操作:
mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener()
@Override
public void onDrawerStateChanged(int newState)
if (newState == DrawerLayout.STATE_SETTLING)
if (!mDrawerLayout.isDrawerOpen(GravityCompat.START))
// Drawer started opening
else
// Drawer started closing
);
【讨论】:
【参考方案5】:对于 Kotlin
var toggle = object : ActionBarDrawerToggle(this,
drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
override fun onDrawerOpened(drawerView: View)
super.onDrawerOpened(drawerView)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
【讨论】:
【参考方案6】:drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
@Override
public void onDrawerOpened(View drawerView)
super.onDrawerOpened(drawerView);
app.sendScreenView("Menu");
;
drawer.setDrawerListener(toggle);
toggle.syncState();
这是最好的方法。
【讨论】:
【参考方案7】:我不明白为什么这里几乎每个人都建议使用沉降,而当抽屉沉降时调用它,而开始打开时则没有?这个问题不是很清楚吗?
如何检测 DrawerLayout 开始打开?
然后我不明白人们如何建议在使用带有 slideOffset 的简单回调时重复调用未知次数直到打开完成的代码,这可能会导致一些未知问题,具体取决于您的实现,它只会浪费性能。你只想知道抽屉什么时候开始打开并且知道一次,而不是 100 次......
我不认为是超级简单的解决方案,但我是这样实现的:
val DrawerLayout.isDrawerOpen get() = isDrawerOpen(START) || isDrawerOpen(END)
fun DrawerLayout.onDrawerOpening(function: (DrawerLayout) -> Unit)
val drawerLayout = this
var onDrawerOpeningCalled = false
addDrawerListener(object : SimpleDrawerListener()
override fun onDrawerSlide(drawerView: View, slideOffset: Float)
super.onDrawerSlide(drawerView, slideOffset)
if (!onDrawerOpeningCalled && slideOffset > 0f && !isDrawerOpen)
function(drawerLayout)
onDrawerOpeningCalled = true
override fun onDrawerStateChanged(newState: Int)
if (newState == STATE_IDLE) onDrawerOpeningCalled = false
)
用法:
drawer.onDrawerOpening
panelView.showingInPager(true) //Just my use case...
【讨论】:
【参考方案8】:福克伍德的答案对我不起作用,但对 if 语句进行了轻微修改就可以了)
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, navigationDrawerLayout, topToolbar,
R.string.open_drawer, R.string.close_drawer)
@Override public void onDrawerStateChanged(int newState)
if (newState == DrawerLayout.STATE_SETTLING && !navigationDrawerLayout.isDrawerOpen(navigationDrawerView))
// this where Drawer start opening
【讨论】:
以上是关于如何检测 DrawerLayout 开始打开?的主要内容,如果未能解决你的问题,请参考以下文章
DrawerLayout 和 NavigationView - 未找到属性“菜单”