本文简单模仿了一般软件的侧滑菜单栏,只有当滑动主视图时,侧边菜单栏才会显示与隐藏,使用的是ViewDragHelper,让ViewDragHelper控制主视图的左右滑动,以达到侧滑菜单出现的假象,实际侧滑菜单一直没动,只有主视图在动。
先上效果
手指左右滑动
侧边栏效果图
自定义控件代码
其继承自FrameLayout,通过拦截触摸事件,将其交给ViewDragHelper处理,将拦截事件也交给ViewDragHelper,设置其何时开始检测触摸,并且设置滑动的子控件,即可实现该效果;
public class DragViewGroup extends FrameLayout {
private ViewDragHelper mHelper;
private View mLeftView;
private View mMainView;
private int mLefeWidth;
public DragViewGroup(@NonNull Context context) {
super(context);
initView();
}
public DragViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initView();
}
public DragViewGroup(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//布局加载完成,可获取两个子控件
mLeftView = getChildAt(0);
mMainView = getChildAt(1);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//此时已测量完成,可获取抽屉的宽度
mLefeWidth = mLeftView.getMeasuredWidth();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//事件拦截任务交给ViewDragHelper
return mHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mHelper.processTouchEvent(event);
//返回true,事件不再向父控件传
return true;
}
private void initView() {
mHelper = ViewDragHelper.create(this,mCallBack);
}
private ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback() {
//何时开始滑动检测
@Override
public boolean tryCaptureView(@NonNull View view, int i) {
//当滑动的对象是mainView时开始检测触摸事件
return view == mMainView;
}
@Override
public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
//处理水平滑动(子view左边界距离当前framelayout左边界距离),返回滑动位置
if (left > 0) {
return left>mLefeWidth ? mLefeWidth : left;
} else {
return 0;
}
}
@Override
public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
//处理垂直滑动,返回垂直滑动位置
return 0;
}
@Override
public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起时处理
if (mMainView.getLeft()>mLefeWidth/2) {
//让左边菜单栏完全展示
mHelper.smoothSlideViewTo(mMainView,mLefeWidth,0);
//它执行后会调用到computerScroll()
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
} else {
//让左边菜单栏隐藏
mHelper.smoothSlideViewTo(mMainView,0,0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
};
@Override
public void computeScroll() {
//如果滑动还未结束
if (mHelper.continueSettling(true)) {
//继续调用computeScroll
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
}
布局文件
由于DragViewGroup是FrameLayout,可以看到实际上侧边栏和主视图是重叠的,滑动的是主视图,移动的也是主视图,侧边栏始终未变;
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="170dp"
android:layout_height="match_parent"
android:background="@color/colorPrimary">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent">