美文网首页程序人生
Android Drawerlayout侧滑冲突注意事项

Android Drawerlayout侧滑冲突注意事项

作者: 为自己代颜_ | 来源:发表于2022-09-09 17:34 被阅读0次

1 DrawerLayout界面点击事件穿透问题,即点击Drawerlayout上面的区域,会发现该位置DrawerLayout覆盖掉的区域的控件可以被点击 解决方案如下:

       //这里设置clickable(true)  必须动态设置  静态设置没有效果
        //解决问题   侧滑菜单出来的时候 点击菜单上的区域会有点击穿透问题

        mDrawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() {
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
            }
            @Override
            public void onDrawerOpened(View drawerView) {
                drawerView.setClickable(true);
            }
            @Override
            public void onDrawerClosed(View drawerView) {
            }
            @Override
            public void onDrawerStateChanged(int newState) {
            }
        });
  1. 处理DrawerLayout全屏滑动(默认不会全屏滑动)、然后屏蔽掉长按会弹抽屉的方式
/**
     * 向右边滑
     * 处理DrawerLayout全屏滑动(默认不会全屏滑动)、然后屏蔽掉长按会弹抽屉的方式
 * @param displayWidthPercentage 1.0表示全屏可滑动 0.5只有右半部分可滑屏 0表示没有滑动事件
     */
    fun setDrawerRightEdgeSize(
        activity: Activity,
        drawerLayout: DrawerLayout,
        displayWidthPercentage: Float
    ) {
        if (activity == null || drawerLayout == null) return
        try {
            // 找到 ViewDragHelper 并设置 Accessible 为true
            val leftDraggerField: Field =
                drawerLayout.javaClass.getDeclaredField("mLeftDragger") //Right
            // true表示可全屏滑动
            leftDraggerField.isAccessible = true
            val leftDragger: ViewDragHelper = leftDraggerField[drawerLayout] as ViewDragHelper

            // 找到 edgeSizeField 并设置 Accessible 为true
            val edgeSizeField: Field = leftDragger.javaClass.getDeclaredField("mEdgeSize")
            // true表示可全屏滑动
            edgeSizeField.isAccessible = true
            val edgeSize = edgeSizeField.getInt(leftDragger)

            // 设置新的边缘大小
            val displaySize = Point()
            activity.windowManager.defaultDisplay.getSize(displaySize)
            edgeSizeField.setInt(
                leftDragger, Math.max(
                    edgeSize, (displaySize.x *
                            displayWidthPercentage).toInt()
                )
            )

            //获取 Layout 的 ViewDragCallBack 实例“mLeftCallback”
            //更改其属性 mPeekRunnable
            val leftCallbackField: Field =
                drawerLayout.javaClass.getDeclaredField("mLeftCallback")
            // true 表示不可长按弹窗
            leftCallbackField.isAccessible = true

            //因为无法直接访问私有内部类,所以该私有内部类实现的接口非常重要,通过多态的方式获取实例
            val leftCallback: ViewDragHelper.Callback =
                leftCallbackField[drawerLayout] as ViewDragHelper.Callback
            val peekRunnableField: Field = leftCallback.javaClass.getDeclaredField("mPeekRunnable")

            // true 表示不可长按弹窗
            peekRunnableField.isAccessible = true
            peekRunnableField[leftCallback] = Runnable {}
        } catch (e: NoSuchFieldException) {
        } catch (e: IllegalArgumentException) {
        } catch (e: IllegalAccessException) {
        }
    }
  1. Android中DrawerLayout+ViewPager滑动冲突及类似侧滑抽屉内列表数据条目侧滑冲突的解决方法

首先,让我们先来解决 DrawerLayout 和 ViewPager 的侧滑事件冲突。当 DrawerLayout 中嵌套 ViewPager 时,侧滑默认是执行 DrawerLayout 的侧滑事件,因为 Android 的事件分发是从 外层 ViewGroup 向里逐级传递到 View 的。
所以会先执行 DrawerLayout 的 onTouchEvent 方法:

@Override
public boolean onTouchEvent(MotionEvent ev) {
 mLeftDragger.processTouchEvent(ev); 
 mRightDragger.processTouchEvent(ev); 
 final int action = ev.getAction(); boolean wantTouchEvents = true; 
 switch (action & MotionEventCompat.ACTION_MASK) { 
  case MotionEvent.ACTION_DOWN: { 
   final float x = ev.getX(); 
   final float y = ev.getY(); 
   mInitialMotionX = x; 
   mInitialMotionY = y; 
   mDisallowInterceptRequested = false; 
   mChildrenCanceledTouch = false; 
   break; 
  } 
  case MotionEvent.ACTION_UP: { 
   final float x = ev.getX(); 
   final float y = ev.getY(); 
   boolean peekingOnly = true;
   final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y); 
   if (touchedView != null && isContentView(touchedView)) { 
    final float dx = x - mInitialMotionX; 
    final float dy = y - mInitialMotionY; 
    final int slop = mLeftDragger.getTouchSlop(); 
    if (dx * dx + dy * dy < slop * slop) { 
     // Taps close a dimmed open drawer but only if it isn't locked open. 
     final View openDrawer = findOpenDrawer(); 
     if (openDrawer != null) { 
      peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN; 
     } 
    } 
    } 
   closeDrawers(peekingOnly); 
   mDisallowInterceptRequested = false; 
   break; 
  } 
  case MotionEvent.ACTION_CANCEL: { 
   closeDrawers(true); 
   mDisallowInterceptRequested = false;
   mChildrenCanceledTouch = false; break; 
  } 
 } 
 return wantTouchEvents;
}

可以看到在最后始终返回 wantTouchEvents,也就是返回 true,意味着点击事件在 DrawerLayout 就被消费掉了,无法传到 ViewPager。

所以,我们像下面这样,监听当 Drawer 打开时,将 DrawerLayout 设置为 LOCK_MODE_LOCKED_OPEN,这样在 Drawer 被打开时,就能够触发 ViewPager 的滑动事件了。

mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() { 
 @Override 
 public void onDrawerSlide(View drawerView, float slideOffset) {

 }

 @Override 
 public void onDrawerOpened(View drawerView) {
 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
 }

 @Override public void onDrawerClosed(View drawerView) {
 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); 
 }

 @Override public void onDrawerStateChanged(int newState) {

 }
});

但是,当侧边栏的 ViewPager 滑动到最后一页,再向左滑动时,我们会希望能够自然的关闭 Drawer。这就需要我们监听 ViewPager 的 PageChange 事件,当滑动到最后一页时,将 DrawerLayout 的 LockMode 设置回 LOCK_MODE_UNLOCKED。

然后让 MainActivity 实现这个:

@Override
public void onPageSelected(boolean isLast) { 
 if (isLast) { 
 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
 } else if (mDrawerLayout.getDrawerLockMode(GravityCompat.START) == DrawerLayout.LOCK_MODE_UNLOCKED) {
 mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN); 
 }
}

相关文章

网友评论

    本文标题:Android Drawerlayout侧滑冲突注意事项

    本文链接:https://www.haomeiwen.com/subject/zahznrtx.html