700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android自定义View 实现全屏滑动的DrawerLayout

Android自定义View 实现全屏滑动的DrawerLayout

时间:2023-01-14 18:01:02

相关推荐

Android自定义View 实现全屏滑动的DrawerLayout

转载请标明出处:/weixin_39059543/article/details/73826250

对与DrawerLayout大家应该用过,是Google官方推出的一种抽屉式导航控件。打开左右两边菜单的方式是从手机屏

幕的边缘处滑动来触发,不过总有些**的需求要让它可以全屏滑动触发菜单,网上也有一些解决办法,无非就是用

setDrawerLeftEdgeSize()来设置边缘大小,将一边的屏幕边缘扩大至整个屏幕,不过这会产生一些bug比如点击屏幕或上下滑动屏幕都会弹出菜单、多种手势不能识别,并且只能实现一边的全屏滑动,因为不能两边的边缘都扩大至全屏。所以要想从根本上解决这个这个问题,就要从源码上分析。

我们来看一下DrawerLayout的源码:

public class DrawerLayout extends ViewGroup implements DrawerLayoutImpl {private static final String TAG = "DrawerLayout";@IntDef({STATE_IDLE, STATE_DRAGGING, STATE_SETTLING})@Retention(RetentionPolicy.SOURCE)private @interface State {}/*** Indicates that any drawers are in an idle, settled state. No animation is in progress.*/public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;/*** Indicates that a drawer is currently being dragged by the user.*/public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;

它是继承ViewGroup的一个自定义类,所以我们可以仿照它的写法自定义一个MyDrawerLayout 只要在

onTouchEvent(MotionEvent ev)判断用户手势,左右滑动打开相对应用的菜单,原理就是这样。

我们继续看源码打开抽屉的方法:

@Overridepublic void onEdgeDragStarted(int edgeFlags, int pointerId) {final View toCapture;if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {toCapture = findDrawerWithGravity(Gravity.LEFT);} else {toCapture = findDrawerWithGravity(Gravity.RIGHT);}if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {mDragger.captureChildView(toCapture, pointerId);}}

这个方法是当用户触发手机屏幕边缘的时候回调,我们可以将这个方法屏蔽掉,然后在

onTouchEvent(MotionEventev)里调用打开方法。

private static final int MIN_DRAWER_MARGIN = 64; // dp

注意一下源码中这个这是设置菜单的最大宽度离另一边的最小距离,简单来说要想你的菜单是全屏显示的话就把这

个值设置为0。

核心代码:

@Overridepublic boolean onTouchEvent(MotionEvent ev) {mLeftDragger.processTouchEvent(ev);mRightDragger.processTouchEvent(ev);final View toCapture;final int action = ev.getAction();boolean wantTouchEvents = true;if (ev.getPointerCount() > 1) { //多点触屏拦截,防止多点触屏滑出菜单 如果主内容里面有子内控件,可写到onInterceptTouchEvent交给子类拦截return false;}switch (action & MotionEventCompat.ACTION_MASK) {case MotionEvent.ACTION_DOWN: {final float x = ev.getX();final float y = ev.getY();mInitialMotionX = x;mInitialMotionY = y;closeDrawers(true);closeKeyboard();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;isCheck = false;break;}case MotionEvent.ACTION_CANCEL: {closeDrawers(true);mDisallowInterceptRequested = false;mChildrenCanceledTouch = false;break;}//核心代码 滑动打开菜单case MotionEvent.ACTION_MOVE: { if (findDrawerWithGravity(Gravity.END).getVisibility() != View.VISIBLE && findDrawerWithGravity(Gravity.START).getVisibility() != View.VISIBLE) {final float x = ev.getX();final float dx = x - mInitialMotionX;if (dx > 10) {//isCheck为全局变量,用来控制每次滑动只能滑动一侧菜单if (!isCheck) {toCapture = findDrawerWithGravity(Gravity.START);if (getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED){mLeftDragger.captureChildView(toCapture,ev.getPointerId(0));}isCheck = true;}} else if ((dx < -10)) {if (!isCheck) {toCapture = findDrawerWithGravity(Gravity.END);if (getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {mRightDragger.captureChildView(toCapture, ev.getPointerId(0));}isCheck = true;}}}break;}}return wantTouchEvents;}

如果主内容里面有子控件,触摸拦截与传递在子父类的onIntercptTouchEvent和onTouchEvent的这两个方法中处理事件分发。

好了废话不多说,提供源码下载,自己分析:

/download/weixin_39059543/11615398

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。