ViewDragHelper实现微信侧滑
2015-12-25 14:51
716 查看
本文是参考开源的代码进行修改获得的,https://github.com/BlueMor/DragLayout
具体实现已经都在代码中添加了注解,
public class SlideDrawLayout extends FrameLayout {
private Context mContext;
private View mLeftContainer;
private View mMainContainer;
private ViewDragHelper dragHelper;
private int mDragTotalDis;
private int mMainToLeftDis; // 就记录主View的左边距离
private int mWidth;
private int mHeight;
private int mLeftWidth;
private int mLeftLayoutDis;
private int mLeftScrollDis;
public SlideDrawLayout(Context context) {
this(context, null, -1);
}
public SlideDrawLayout(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public SlideDrawLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context) {
mContext = context;
// 第二参数,配置拖动的敏感度
dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
//决定chlid是否可被拖动
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mLeftContainer || child == mMainContainer;
}
// 当View正被拖着时
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (releasedChild == mMainContainer) {
if (mMainToLeftDis > mDragTotalDis / 3) {
open();
} else {
close();
}
} else if (releasedChild == mLeftContainer) {
if (mMainToLeftDis < mDragTotalDis / 3) {
close();
} else {
open();
}
}
}
// 横向拖拽的范围,大于0时可拖拽,等于0无法拖拽
// 此方法只用于计算如view释放速度,敏感度等
// 实际拖拽范围由clampViewPositionHorizontal方法设置
@Override
public int getViewHorizontalDragRange(View child) {
return super.getViewHorizontalDragRange(child);
}
//返回的是拖动的范围,如果当前移动的超过了,不能继续拖动
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (mMainToLeftDis + dx < 0) {
return 0;
} else if (mMainToLeftDis + dx > mDragTotalDis) {
return mDragTotalDis;
}
return left;
}
// 当View位置发生变化,
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == mMainContainer) {
mMainToLeftDis = left;
} else {// 当是左边的View时, left,就是左边View的值了,
mMainToLeftDis += dx;
}
// 进行值的修正
if (mMainToLeftDis < 0) {
mMainToLeftDis = 0;
} else if (mMainToLeftDis > mDragTotalDis) {
mMainToLeftDis = mDragTotalDis;
}
// 如果拖拽的是左面板,强制在指定位置绘制Content
if (changedView == mLeftContainer) {
layoutContent();
}
dispatchDragEvent(mMainToLeftDis);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return super.clampViewPositionVertical(child, top, dy);
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return dragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
dragHelper.processTouchEvent(event);
return true;
}
private void layoutContent() {
mMainContainer.layout(mMainToLeftDis, 0, mMainToLeftDis + mWidth, mHeight);
mLeftContainer.layout(0, 0, mWidth, mHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
mMainContainer.layout(mMainToLeftDis, 0, mMainToLeftDis + mWidth, mHeight);
mLeftContainer.layout(0, 0, mLeftWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 初始移动一定距离
ViewHelper.setTranslationX(mLeftContainer, -mLeftLayoutDis);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
if (mLeftContainer != null) {
mLeftWidth = mLeftContainer.getMeasuredWidth();
mLeftLayoutDis = mLeftWidth / 3;
mDragTotalDis = mLeftWidth;
mLeftScrollDis = mLeftLayoutDis;
}
}
/**
* 每次更新都会调用 根据当前执行的位置计算百分比percent
*/
protected void dispatchDragEvent(int left) {
float percent = left / (float) mDragTotalDis;
animViews(percent);
}
/**
* 伴随动画:
*
* @param percent
*/
private void animViews(float percent) {
float leftDis = -mLeftScrollDis + mLeftScrollDis * percent;
ViewHelper.setTranslationX(mLeftContainer, leftDis);
}
public void close() {
close(true);
}
public void open() {
open(true);
}
public void close(boolean isSmooth) {
mMainToLeftDis = 0;
if (isSmooth) {
// 执行动画,返回true代表有未完成的动画, 需要继续执行
if (dragHelper.smoothSlideViewTo(mMainContainer, mMainToLeftDis, 0)) {
// 注意:参数传递根ViewGroup
ViewCompat.postInvalidateOnAnimation(this);
}
} else {
layoutContent();
}
}
public void open(boolean isSmooth) {
mMainToLeftDis = mDragTotalDis;
if (isSmooth) {
if (dragHelper.smoothSlideViewTo(mMainContainer, mMainToLeftDis, 0)) {
ViewCompat.postInvalidateOnAnimation(this);
}
} else {
layoutContent();
}
}
@Override
public void computeScroll() {
//
if (dragHelper.continueSettling(true)) { // true 决定后面继续执行,
ViewCompat.postInvalidateOnAnimation(this);
}
}
/**
* 填充结束时获得两个子布局的引用
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
int childCount = getChildCount();
// 必要的检验
if (childCount < 2) {
throw new IllegalStateException(
"You need two childrens in your content");
}
if (!(getChildAt(0) instanceof ViewGroup)
|| !(getChildAt(1) instanceof ViewGroup)) {
throw new IllegalArgumentException(
"Your childrens must be an instance of ViewGroup");
}
mLeftContainer = getChildAt(0);
mMainContainer = getChildAt(1);
}
}
具体实现已经都在代码中添加了注解,
public class SlideDrawLayout extends FrameLayout {
private Context mContext;
private View mLeftContainer;
private View mMainContainer;
private ViewDragHelper dragHelper;
private int mDragTotalDis;
private int mMainToLeftDis; // 就记录主View的左边距离
private int mWidth;
private int mHeight;
private int mLeftWidth;
private int mLeftLayoutDis;
private int mLeftScrollDis;
public SlideDrawLayout(Context context) {
this(context, null, -1);
}
public SlideDrawLayout(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public SlideDrawLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context) {
mContext = context;
// 第二参数,配置拖动的敏感度
dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
//决定chlid是否可被拖动
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mLeftContainer || child == mMainContainer;
}
// 当View正被拖着时
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (releasedChild == mMainContainer) {
if (mMainToLeftDis > mDragTotalDis / 3) {
open();
} else {
close();
}
} else if (releasedChild == mLeftContainer) {
if (mMainToLeftDis < mDragTotalDis / 3) {
close();
} else {
open();
}
}
}
// 横向拖拽的范围,大于0时可拖拽,等于0无法拖拽
// 此方法只用于计算如view释放速度,敏感度等
// 实际拖拽范围由clampViewPositionHorizontal方法设置
@Override
public int getViewHorizontalDragRange(View child) {
return super.getViewHorizontalDragRange(child);
}
//返回的是拖动的范围,如果当前移动的超过了,不能继续拖动
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (mMainToLeftDis + dx < 0) {
return 0;
} else if (mMainToLeftDis + dx > mDragTotalDis) {
return mDragTotalDis;
}
return left;
}
// 当View位置发生变化,
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == mMainContainer) {
mMainToLeftDis = left;
} else {// 当是左边的View时, left,就是左边View的值了,
mMainToLeftDis += dx;
}
// 进行值的修正
if (mMainToLeftDis < 0) {
mMainToLeftDis = 0;
} else if (mMainToLeftDis > mDragTotalDis) {
mMainToLeftDis = mDragTotalDis;
}
// 如果拖拽的是左面板,强制在指定位置绘制Content
if (changedView == mLeftContainer) {
layoutContent();
}
dispatchDragEvent(mMainToLeftDis);
}
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
return super.clampViewPositionVertical(child, top, dy);
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return dragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
dragHelper.processTouchEvent(event);
return true;
}
private void layoutContent() {
mMainContainer.layout(mMainToLeftDis, 0, mMainToLeftDis + mWidth, mHeight);
mLeftContainer.layout(0, 0, mWidth, mHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
mMainContainer.layout(mMainToLeftDis, 0, mMainToLeftDis + mWidth, mHeight);
mLeftContainer.layout(0, 0, mLeftWidth, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 初始移动一定距离
ViewHelper.setTranslationX(mLeftContainer, -mLeftLayoutDis);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
if (mLeftContainer != null) {
mLeftWidth = mLeftContainer.getMeasuredWidth();
mLeftLayoutDis = mLeftWidth / 3;
mDragTotalDis = mLeftWidth;
mLeftScrollDis = mLeftLayoutDis;
}
}
/**
* 每次更新都会调用 根据当前执行的位置计算百分比percent
*/
protected void dispatchDragEvent(int left) {
float percent = left / (float) mDragTotalDis;
animViews(percent);
}
/**
* 伴随动画:
*
* @param percent
*/
private void animViews(float percent) {
float leftDis = -mLeftScrollDis + mLeftScrollDis * percent;
ViewHelper.setTranslationX(mLeftContainer, leftDis);
}
public void close() {
close(true);
}
public void open() {
open(true);
}
public void close(boolean isSmooth) {
mMainToLeftDis = 0;
if (isSmooth) {
// 执行动画,返回true代表有未完成的动画, 需要继续执行
if (dragHelper.smoothSlideViewTo(mMainContainer, mMainToLeftDis, 0)) {
// 注意:参数传递根ViewGroup
ViewCompat.postInvalidateOnAnimation(this);
}
} else {
layoutContent();
}
}
public void open(boolean isSmooth) {
mMainToLeftDis = mDragTotalDis;
if (isSmooth) {
if (dragHelper.smoothSlideViewTo(mMainContainer, mMainToLeftDis, 0)) {
ViewCompat.postInvalidateOnAnimation(this);
}
} else {
layoutContent();
}
}
@Override
public void computeScroll() {
//
if (dragHelper.continueSettling(true)) { // true 决定后面继续执行,
ViewCompat.postInvalidateOnAnimation(this);
}
}
/**
* 填充结束时获得两个子布局的引用
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
int childCount = getChildCount();
// 必要的检验
if (childCount < 2) {
throw new IllegalStateException(
"You need two childrens in your content");
}
if (!(getChildAt(0) instanceof ViewGroup)
|| !(getChildAt(1) instanceof ViewGroup)) {
throw new IllegalArgumentException(
"Your childrens must be an instance of ViewGroup");
}
mLeftContainer = getChildAt(0);
mMainContainer = getChildAt(1);
}
}
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories