最近做项目的时候需要用到DrawerLayout做侧边栏,当然自己也可以通过用ViewDragHelper来实现侧边栏优点是可高度定制化,但是比较繁琐。而DrawerLayout是系统封装好的控件,用起来简单。DrawerLayout本身内部也会通过ViewDragHelper 实现的。言归正传,系统自带的DrawLayout只能实现从屏幕边缘滑出菜单,现在需求是全屏幕任何位置都能滑出。有两种方法可以实现:
方法一:.通过反射,改变DrawerLayout的一个私有属性mEdgeSize,调整滑动范围
该方法是stackfloweOver 上的,这里找不到原链接了
Field mDragger = null;
try {
mDragger = drawerLayout.getClass().getDeclaredField(
"mLeftDragger"); //mRightDragger for right obviously
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mDragger.setAccessible(true);
ViewDragHelper draggerObj = null;
try {
draggerObj = (ViewDragHelper) mDragger
.get(drawerLayout);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Field mEdgeSize = null;
try {
mEdgeSize = draggerObj.getClass().getDeclaredField(
"mEdgeSize");
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mEdgeSize.setAccessible(true);
int edge = 0;
try {
edge = mEdgeSize.getInt(draggerObj);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
mEdgeSize.setInt(draggerObj, edge * 7); //optimal value as for me, you may set any constant in dp
//You can set it even to the value you want like mEdgeSize.setInt(draggerObj, 150); for 150dp
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
方法二:通过拦截Activity触摸事件的分发,实现全屏滑出菜单
在Acvtivity中,重写dispatchTouchEvent事件.简单的介绍Android 触摸事件的传递,Activity->PhoneWindow->DecorView->布局文件的根目录(也就是setContentView中传递的view)
private GestureDetector gestureDetector;
@Override
public void onCreate(Bundle b){
super.onCreate(b);
setContentView(R.layout.activity_main);
gestureDetector=new GestureDetector(this,new GestureDetector.SimpleOnGestureListener(){
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//判断是否是右滑
float offsetX=e2.getX()-e1.getX();
float offsetY=e2.getY()-e1.getY();
if ((offsetX > 0 && offsetX > Math.abs(offsetY)) || (velocityX > 0 && velocityX > Math.abs(velocityY))) {
return true;//返回true表示我们在dispatchTouchEvent中,就不把事件传递到子控件中了
}
return false;
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent event){
//当向右滑动的时候,拦截事件,不传下去,通过GestureDetector辅助事件的判断
if(gestureDetector.onTouchEvent(event)){
//打开侧边栏
drawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.dispatchTouchEvent(event);
}
这两种方法都有各自的问题。
第一种方法,反射修改DrawerLayout的mEdgeSize参数,在DrawerLayout中嵌入ListView时,长按ListView的item会导致侧边栏的滑出
第二种方法,没有了菜单滑出的跟随效果,只有一整个滑动事件完成(即手松开,或者横向滑动速度大于纵向滑动速度时)菜单才会滑出,不会滑动一点菜单出现一点。
如果有更好的方法,请多多指教