【问题标题】:Android Navigation Drawer bug using the sampleAndroid Navigation Drawer bug 使用示例
【发布时间】:2013-08-04 14:57:40
【问题描述】:

我正在尝试基于我的应用实现抽屉式导航模式。我从here 下载了示例代码并运行了它,90% 的情况下抽屉都可以正常工作,但有时当我尝试打开抽屉时它会卡住。我有办法复制这种情况,但并不总是有效。我要做的是:

1- 按原样运行示例代码。
2- 将手指放在左边缘以查看抽屉
3- 松开手指并将其按在主要片段上
4- 尝试像往常一样打开抽屉

有时,无论您向右滑动多少手指以进一步打开抽屉,抽屉都会卡在窥视模式。有没有人解决过这个问题?

【问题讨论】:

标签: android sample navigation-drawer


【解决方案1】:

我遇到了您提到的类似问题。我在相对布局 (FILL_PARENT) 中有一个列表视图。每当列表视图中的内容较少时,当我在列表视图之外的区域中拖动时,导航抽屉就会被击中。为相对布局设置android:clickable="true" 解决了这个问题。希望这可能会有所帮助。

【讨论】:

  • 你已经在导航抽屉的相对布局中设置了 android:clickable="true" 你有 listview 吗?
  • 您需要将clickable="true" 设置为用于保存主要内容的任何布局。
【解决方案2】:

为了澄清 Viji 的回答,如果您使用的是提供的导航抽屉示例:

<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         The drawer is given a fixed width in dp and extends the full height of
         the container. A solid background is used for contrast
         with the content view. -->
    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>

android:clickable="true" 添加到 FrameLayout 似乎可以解决问题。

【讨论】:

    【解决方案3】:

    两种解决方案。

    1. 设置android:clickable
    2. 复制drawerlayout的源代码并删除peekDrawer功能以禁用该功能

    让我解释一下为什么会出现这个错误。

    DrawerLayout 三种状态 STATE_IDLE、STATE_DRAGGING、STATE_SETTLING

    ACTION_DOWN-> onEdgeTouched will be triggered if it is on the edge, DrawerLayout will trigger peekDrawer after 120ms
    

    PeekDrawer 实际上是将 DrawerLayout 的状态更改为 STATE_SETTLING,然后让 Drawer 滚动到指定位置。然后将状态设置为 IDLE。

    ACTION_MOVE-> 
    
    If the current state is DRAGGING, drag captureView
    
    If the current state is not DRAGGING, it will try to execute tryCaptureViewForDrag to reset the state to DRAGGING.
    
    And at the same time, it will also determine whether a new edge gesture is triggered (emphasis !!)
    
    If a new edge gesture was dete, it will invoke onEdgeDragStared
    and DrawerLayout will go to captureView to captrue the drawer
    
    

    这个bug怎么重现?

    • 首先点击边缘调用 120ms 延迟函数peekDrawer
    • 在调用 peekDrawer 之前,触发 onEdgeDragStared 让抽屉布局捕获抽屉,dragState 将设置为 STATE_DRAGGING
    • 120ms后,如果手指还在drawerLayout想要查看的区域,dragState会被设置为SETTLING
    • 在drawer peek到目的地之前,将手指快速移出peek结束前的那个区域,drawer不会跟随你的手指,因为状态是SETTLING,SETTLING后状态将设置为IDLE
    • 现在你的手指完全离开了抽屉,状态是 IDLE ,所以你不能再拖动视图了

    所以,解决方案是停止 peekDrawer 实际上,drawerlayout 已经解决了这个问题。

        public boolean onInterceptTouchEvent(MotionEvent ev) {
            switch (action) {
    
                case MotionEvent.ACTION_MOVE: {
                    // If we cross the touch slop, don't perform the delayed peek for an edge touch.
                    if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
                        mLeftCallback.removeCallbacks();
                        mRightCallback.removeCallbacks();
                    }
                    break;
                }
    
            }
    
            return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
        }
    
    

    如果孩子是可点击的,孩子会消费事件,onInterceptTouchEvent会调用很多次。并在移动时移除 peekDraw。

    【讨论】:

      猜你喜欢
      • 2014-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多