使用DrawerLayout可以很方便的完成抽屉布局,但如果你的DrawerLayout是覆盖在另一个布局之上的,那DrawerLayout下面的所有界面都无法收到onTouch事件,翻阅源码,查看DrawerLayout的onTouch方法:
@Override
public boolean onTouchEvent(MotionEvent ev) {
...
boolean wantTouchEvents = true;
...
return wantTouchEvents;
}
发现该方法内有一个wantTouchEvents参数,并且设为默认值后不做任何修改直接返回,也就是说DrawerLayout将会拦截所有点击事件不向下传递。
到这里很自然的会想到重写该方法,将返回值修改为false不就可以让底层界面收到点击事件了?于是有了修改如下:
public class CustomDrawerLayout extends DrawerLayout {
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return false;
}
}
修改完后发现,确实事件可以正常向下传递了,但也引发了其他问题,抽屉不能正常滑动了,说明我们不能一股脑的把事件都向下传递,如果当前正在滑动抽屉时事件不传递。针对此问题,我们需要解决两个问题:
1.我们知道抽屉是在滑动边缘位置时触发的,所以我们需要判断事件是否落在边缘区域
2.如果当前抽屉正处于滑动状态,则事件不向下传递
针对第一点,查看源码发现,边缘宽度的定义放在ViewDragHelper中:
public class ViewDragHelper {
private static final int EDGE_SIZE = 20; // dp
private int mEdgeSize;
private ViewDragHelper(@NonNull Context context, @NonNull ViewGroup forParent,@NonNull Callback cb) {
...
final float density = context.getResources().getDisplayMetrics().density;
mEdgeSize = (int) (EDGE_SIZE * density + 0.5f);
...
}
}
针对第二点,DrawerLayout有两个public方法可以判断:
public boolean isDrawerOpen(@EdgeGravity int drawerGravity) {}
public boolean isDrawerVisible(@EdgeGravity int drawerGravity) {}
传入抽屉方向即可获取当前是否有展示抽屉
最终可运行代码如下:
public class CustomDrawerLayout extends DrawerLayout {
private static final int EDGE_SIZE = 20; // dp
private float mEdgeSize;
public CustomDrawerLayout(@NonNull Context context) {
this(context, null);
}
public CustomDrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomDrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final float density = context.getResources().getDisplayMetrics().density;
mEdgeSize = EDGE_SIZE * density + 0.5f;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean superResult = super.onTouchEvent(event);
if (isEdge(event) || isDrawerOpen(GravityCompat.START) || isDrawerVisible(GravityCompat.START)
|| isDrawerOpen(GravityCompat.END) || isDrawerVisible(GravityCompat.END)) {
return superResult;
} else {
return false;
}
}
private boolean isEdge(MotionEvent event) {
return event.getX() <= mEdgeSize || event.getX() >= (getWidth() - mEdgeSize);
}
}
网友评论