拖拽滑动效果如下:
setContentView(R.layout.activity_main);
布局:activity_main.xml
<com.android.myapplication.DragViewGroup
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/menu_layout"
android:layout_width="50dp"
android:layout_height="match_parent"
android:text="menu"/>
<TextView
android:id="@+id/main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/darker_gray"/>
com.android.myapplication.DragViewGroup>
ViewDragHelper的相关代码如下。
package com.android.myapplication;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
/**
* Top Secret, Copyright (C) TRANSSION HOLDINGS.
* Any fragment herein shall not be copied, saved, quoted or spread without TRANSSION HOLDINGS' written authorization.
*
* @class describe
*/
public class DragViewGroup extends FrameLayout {
public DragViewGroup(Context context) {
super(context, null);
initView();
}
public DragViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView();
}
private ViewDragHelper mViewDragHelper;
public void initView() {
if (mViewDragHelper != null) {
return;
}
/**
* ViewDragHelper 通常定义在一个ViewGroup的内部,并通过其静态工厂方法进行初始化。
*它的第一个参数是要监听的View,通常需要是一个ViewGroup,即parentView;第二个参数是一个Callback 回调,这个回调就是整个ViewDragHelp的逻辑核心
*/
mViewDragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
/**
* 通过这个方法,我们可以指定在创建ViewDragHelper时,参数parentView中的哪个子View可以被移动,
* 例如这个实例中自定义了一个ViewGroup,里面定义了两个 子View(menuView mainView),
* 当指定如下代码时,则只有MainView是可以被拖动的。
* @param child
* @param pointerId
* @return
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
//若果当前触摸的child是mMainView时开始检测
return child == mMainView;
}
/**
* 水平方向的滑动。默认返回值是0,即不发生滑动。
* @param child
* @param left 水平方向上child移动的距离。
* @param dx 比较前一次的增量
* @return
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
Log.i("wlj", "left === " + left + " dx = " + dx);
if (left > 0) {
return Math.min(left, mMenuViewWidth);
}
return 0;
}
/**
* 垂直方向的滑动,默认返回值是0,即不发生滑动。
* @param child
* @param top 垂直方向上child移动的距离
* @param dy 比较前一次的增量
* @return
*/
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
/**
* 拖拽结束时调用
* 当然,这个方法内部是通过Scroller来实现的,这也是需要重写computeScroll()方法的原因。
* @param releasedChild
* @param xvel
* @param yvel
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//手指抬起后缓慢移动到指定位置
if (mMainView.getLeft() < 300) {
//关闭菜单,相当于Scroller的startScroll方法
mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
} else {
//打开菜单
mViewDragHelper.smoothSlideViewTo(mMainView, mMenuViewWidth, 0);
ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
}
}
});
}
View mMainView;
View mMenuView;
int mMenuViewWidth = 0;
/**
* 加载完布局文件后调用
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mMenuView = getChildAt(0);
mMainView = getChildAt(1);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//获取View的宽度,(需要根据View的宽度来处理滑动后的效果)
mMenuViewWidth = mMenuView.getMeasuredWidth();
}
/**
* 重写事件拦截方法,将事件传给ViewDragHelper进行处理
*
* @param ev
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
/**将触摸事件传递给ViewDragHelper,此操作必不可少
*/
mViewDragHelper.processTouchEvent(event);
return true;
}
/**
* ViewDragHelper 同样需要重写下ComputeScroll()方法,因为ViewDragHelper内部也是通过Scroller来实现平滑移动的。
* 通常情况下,可以使用如下所示的模块代码
*/
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
}
ViewDragHelper 的很多强大的功能还没能够得到展示,在ViewDragHelper.Callnack 中,系统定义了大量的监听事件来帮助我们处理各种事件,下面就列举一些事件。
1.onViewCaptured():这个事件在用户触摸到View后调用。
2.onViewDragStateChanged():这个事件在拖拽状态改变时回调。比如idle,dragging 等状态
3.onViewPositionChanged():这个事件在位置改变时回调,常用于滑动时更改Scale等进行缩放等效果。