仿造微信界面左右拖拽的UI

来源:互联网 发布:中国项目数据分析师网 编辑:程序博客网 时间:2024/04/29 18:01
*知识点:
在右侧动画的时候只能用属性动画,并做兼容
float scale = 0.3f + left * 0.7f / mLeftWidth;
ViewHelper.setScaleX(mLeftView,
scale);
ViewHelper.setScaleY(mLeftView,
scale);
注:属性动画在3.0之后才有的
需要9oldAnimator



自定义的DragLayout
public class DragLayout
extends FrameLayout {
public static final int STATE_IDLE = 0;//空闲状态
public static final int STATE_DRAGING = 1;//正在拖拽的状态
public static final int STATE_FLING = 2;//快速的滑动的状态

private static final String TAG = "DragLayout";
private View mLeftView;// 左侧的view
private View mRightView;// 右侧的view
private View mMainView;//中间的View
private float mLeftWidth;//左侧view的宽度
private float mRightWidth;//右侧view的宽度
private boolean hasLeft;//有左侧的view
private boolean hasRight;//有右侧的view
private ViewDragHelper mDragHelper;
private int mMinVelocity;
private boolean isLeftOpened = false;//用来记录左侧是否打开
private boolean isRightOpened = false;//用来记录右侧是否打开
private int mCurrentState = STATE_IDLE;//默认为闲置状态

private boolean isTouching = false;//用来记录是否是正在触摸view
private OnLayoutDragListener mListener;//拖拽的监听

private boolean canOpenLeft = true;//默认左侧是可以打开的
private boolean canOpenRight = true;//默认右侧是可以打开的

public DragLayout(Context context) {
this(context,
null);
}

public DragLayout(Context context,
AttributeSet attrs) {
super(context,
attrs);


//常量类,不同的手机获取的值不同
ViewConfiguration configuration = ViewConfiguration.get(context);

//获取系统参考的最小速率
mMinVelocity = configuration.getScaledMinimumFlingVelocity();
}

@Override
protected void onFinishInflate() {
//当xml加载完成的回调
int count = getChildCount();

//不能超过三个View,不能少于2个
if (count > 3 || count < 2) {
throw new IllegalArgumentException("控件个数不对");
}

//找到三个自孩子,和左右view的宽度
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
//分别找到三子孩子
FrameLayout.LayoutParams params = (LayoutParams) view.getLayoutParams();
switch (params.gravity) {
case Gravity.LEFT:
mLeftView = view;
mLeftWidth = params.width;
break;
case Gravity.RIGHT:
mRightView = view;
mRightWidth = params.width;
break;
default:
mMainView = view;
break;
}
}

//要有中间的view,左侧或右侧

if (mMainView == null) {
throw new IllegalArgumentException("没有主view");
}
//判断左右的view是否存在
hasLeft = mLeftView != null;
hasRight = mRightView != null;

//初始化ViewDraghelper----------
mDragHelper = ViewDragHelper.create(this,
new DragCallBack());
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
isTouching = true;
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isTouching = false;
break;
}

return super.dispatchTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
mDragHelper.processTouchEvent(event);
return true;
}

/**
* 左侧的View做动画
*/
private void leftAnimation(int left) {
// 1.从左往右拖动时
if (left < 0 || !hasLeft) {
return;
}

//让左侧的view做动画

//设置中轴
ViewHelper.setPivotX(mLeftView,
mLeftView.getLeft());

ViewHelper.setPivotY(mLeftView,
mLeftView.getMeasuredHeight() / 2);

//1. 缩放
float scale = 0.3f + left * 0.7f / mLeftWidth;
ViewHelper.setScaleX(mLeftView,
scale);
ViewHelper.setScaleY(mLeftView,
scale);

//2. 透明度
ViewHelper.setAlpha(mLeftView,
scale);
}

/**
* 中间的View做动画
*/
private void mainAnimation(int left) {

if (left > 0) {
//从左往右做动画

// 缩放
//设置中轴
ViewHelper.setPivotX(mMainView,
0);

ViewHelper.setPivotY(mMainView,
mMainView.getMeasuredHeight() / 2);

//1. 缩放
float scale = 1.0f - left * 0.2f / mLeftWidth;
ViewHelper.setScaleX(mMainView,
scale);
ViewHelper.setScaleY(mMainView,
scale);

} else {
//从右往左做动画
// 缩放
//设置中轴
ViewHelper.setPivotX(mMainView,
mMainView.getMeasuredWidth());

ViewHelper.setPivotY(mMainView,
mMainView.getMeasuredHeight() / 2);

//1. 缩放
float scale = 1.0f + left * 0.2f / mLeftWidth;
ViewHelper.setScaleX(mMainView,
scale);
ViewHelper.setScaleY(mMainView,
scale);
}
}

private void rightAnimation(int left) {

if (left > 0 || !hasRight) {
return;
}
//从右往左滑动


ViewHelper.setPivotX(mRightView,
mRightView.getMeasuredWidth());
ViewHelper.setPivotY(mRightView,
mRightView.getMeasuredHeight() / 2);
//1.缩放动画
float scale = 0.3f - left * 0.7f / mRightWidth;
ViewHelper.setScaleX(mRightView,
scale);
ViewHelper.setScaleY(mRightView,
scale);
}

@Override
public void computeScroll() {
if (mDragHelper.continueSettling(true)) {
invalidate();
}

}

public void setOnLayoutDragListener(OnLayoutDragListener listener) {
this.mListener = listener;
}

/**
* 设置左侧是否可以打开
*
* @param canOpenLeft
*/
public void setCanOpenLeft(boolean canOpenLeft) {
this.canOpenLeft = canOpenLeft;
}

/**
* 设置右侧是否可以打开
*
* @param canOpenRight
*/
public void setCanOpenRight(boolean canOpenRight) {
this.canOpenRight = canOpenRight;
}

public interface OnLayoutDragListener {
//用来暴露左侧是打开还是关闭的
void onLeftToggle(boolean open);

//用来暴露右侧是打开还是关闭的
void onRightToggle(boolean open);

//当状态改变时的回调
void onDragStateChanged(int state);
}

class DragCallBack
extends ViewDragHelper.Callback {


@Override
public boolean tryCaptureView(View view,
int i) {
return mMainView == view;
}

@Override
public int clampViewPositionHorizontal(View child,
int left,
int dx) {
if (child == mMainView) {
if (left > 0 && !canOpenLeft) {
//从左侧往右拖动,左侧不可以打开
return 0;
} else if (left < 0 && !canOpenRight) {
//从右往左侧拖动,右侧不可以打开
return 0;
} else if (left > 0 && left > mLeftWidth) {
// 从左往右拖动, 并且大于左侧的宽度
return (int) (mLeftWidth + 0.5f);
} else if (left < 0 && -left > mRightWidth) {
//从右往左侧拖动,并且拖出的距离大于右侧的宽度
return (int) -(mRightWidth + 0.5f);
}
}

return left;
}

@Override
public void onViewPositionChanged(View changedView,
int left,
int top,
int dx,
int dy) {
invalidate();

if (mMainView == changedView) {
//左侧的View需要做动画,中间的view也需要做动画
leftAnimation(left);

mainAnimation(left);

rightAnimation(left);
}

Log.d(TAG,
"left : " + left);

if (mCurrentState != STATE_DRAGING && mCurrentState != STATE_FLING) {

if (left != 0 && left != mLeftWidth && left != -mRightWidth) {
// 正在拖动 #####
mCurrentState = STATE_DRAGING;

// 回调接口
if (mListener != null) {
mListener.onDragStateChanged(mCurrentState);
}
}
}

// 闲置状态的逻辑-->关闭
if (left == 0 && !isTouching) {
if (dx < 0) {
// 关闭了左侧
//如果从右边往左边走,增量值为 负数
Log.d(TAG,
"关闭左侧");
isLeftOpened = false;

//接口回调
if (mListener != null) {
mListener.onLeftToggle(isLeftOpened);
}

} else {
// 关闭了右侧
Log.d(TAG,
"关闭右侧");

isRightOpened = false;

//回调方法
if (mListener != null) {
mListener.onRightToggle(isRightOpened);
}
}

//手指需要抬起,现在是闲置状态 ####
mCurrentState = STATE_IDLE;

// 回调接口
if (mListener != null) {
mListener.onDragStateChanged(mCurrentState);
}
}

// 闲置状态的逻辑-->左侧打开
if (left == mLeftWidth && !isTouching) {
// 打开了左侧
Log.d(TAG,
"打开了左侧");
isLeftOpened = true;
//接口回调
if (mListener != null) {
mListener.onLeftToggle(isLeftOpened);
}

//手指需要抬起,现在是闲置状态 ####
mCurrentState = STATE_IDLE;

// 回调接口
if (mListener != null) {
mListener.onDragStateChanged(mCurrentState);
}
}

// 闲置状态的逻辑-->右侧打开
if (left == -mRightWidth && !isTouching) {
// 打开了右侧
Log.d(TAG,
"打开了右侧");
isRightOpened = true;
//回调方法
if (mListener != null) {
mListener.onRightToggle(isRightOpened);
}

//手指需要抬起,现在是闲置状态 ####
mCurrentState = STATE_IDLE;

// 回调接口
if (mListener != null) {
mListener.onDragStateChanged(mCurrentState);
}
}

}


@Override
public void onViewReleased(View releasedChild,
float xvel,
float yvel) {
// 手指抬起时的回调

//速率xvel:x方向的速率
Log.d("dragLayout",
"xvel : " + xvel + " minX : " + mMinVelocity);

if (releasedChild == mMainView) {
int left = mMainView.getLeft();

if (left > 0) {
Log.d("DragLayout",
"left : " + left + " width : " + mLeftWidth);
//从左往右拖动的

if (xvel > mMinVelocity && canOpenLeft) {
//应该打开 左侧
//中间的View打开
mDragHelper.smoothSlideViewTo(mMainView,
(int) (mLeftWidth + 0.5f),
0);

//改变状态 ####
mCurrentState = STATE_FLING;

// 回调接口
if (mListener != null) {
mListener.onDragStateChanged(mCurrentState);
}

} else {
//如果拖动的距离不够左侧view的一半,就应该关闭mainView
if (left < mLeftWidth / 2) {


//中间的view关闭
mDragHelper.smoothSlideViewTo(mMainView,
0,
0);
} else {

//中间的View打开
mDragHelper.smoothSlideViewTo(mMainView,
(int) (mLeftWidth + 0.5f),
0);
}
}
} else {
Log.d("DragLayout",
"left : " + left + " width : " + mRightWidth);
if (-xvel > mMinVelocity && canOpenRight) {
//打开右侧
mDragHelper.smoothSlideViewTo(mMainView,
(int) (-mRightWidth - 0.5f),
0);


//改变状态 ####
mCurrentState = STATE_FLING;

// 回调接口
if (mListener != null) {
mListener.onDragStateChanged(mCurrentState);
}
} else {
if (-left > mRightWidth / 2) {
//如果拖动的距离大于 右侧的一半,打开mainView
mDragHelper.smoothSlideViewTo(mMainView,
(int) (-mRightWidth - 0.5f),
0);
} else {
//关闭
mDragHelper.smoothSlideViewTo(mMainView,
0,
0);
}
}
}
invalidate();

}

}
}
}

0 0