package com.xin.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.animation.BounceInterpolator;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.hrg.hefei.R;
/**
* 自定义View实现拖动并自动吸边效果
* <p>
* 处理滑动和贴边 {@link #onTouchEvent(MotionEvent)}
* 处理事件分发 {@link #dispatchTouchEvent(MotionEvent)}
* </p>
*
* @attr customIsAttach //是否需要自动吸边
* @attr customIsDrag //是否可拖曳
*/
public class AttachLayout extends LinearLayout {
private float mLastRawX;
private float mLastRawY;
private final String TAG = "AttachButton";
private boolean isDrug = false;
private int mRootMeasuredWidth = 0;
private int mRootMeasuredHeight = 0;
private int mRootTopY = 0;
private int customAttachDirect; /*-1不吸附 0所有的边 1左 2上 3右 4下 5左右 6上下 */
private boolean customIsDrag;
private boolean touchIsTargetView = true;
private int customIsTargetView;
private View targetView;
public AttachLayout(Context context) {
this(context, null);
}
public AttachLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AttachLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (customIsTargetView > 0) {
targetView = findViewById(customIsTargetView);
}
}
/**
* 初始化自定义属性
*/
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.AttachLayout);
customAttachDirect = mTypedAttay.getInteger(R.styleable.AttachLayout_customAttachDirect, 0);
customIsDrag = mTypedAttay.getBoolean(R.styleable.AttachLayout_customIsDrag, true);
customIsTargetView = mTypedAttay.getResourceId(R.styleable.AttachLayout_customIsTargetView, 0);
mTypedAttay.recycle();
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchIsTargetView = true;
}
if (targetView != null) {
// /*判断是否有目标view,若有不在目标view内不执行*/
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://手指按下
Rect rect = new Rect();
targetView.getHitRect(rect);
if (!rect.contains((int) event.getX(), (int) event.getY())) {
touchIsTargetView = false;
}
}
}
if (touchIsTargetView) {
doTouch(event);
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
//判断是否需要滑动
// doTouch(ev); /*不能放在这,放在这子view收不到事件了*/
//是否拦截事件
if (isDrug) {
return true;
}
return super.onTouchEvent(ev);
}
private void doTouch(MotionEvent ev) {
if (customIsDrag) {
//当前手指的坐标
float mRawX = ev.getRawX();
float mRawY = ev.getRawY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN://手指按下
isDrug = false;
//记录按下的位置
mLastRawX = mRawX;
mLastRawY = mRawY;
ViewGroup mViewGroup = (ViewGroup) getParent();
if (mViewGroup != null) {
int[] location = new int[2];
mViewGroup.getLocationInWindow(location);
//获取父布局的高度
mRootMeasuredHeight = mViewGroup.getMeasuredHeight();
mRootMeasuredWidth = mViewGroup.getMeasuredWidth();
//获取父布局顶点的坐标
mRootTopY = location[1];
}
break;
case MotionEvent.ACTION_MOVE://手指滑动
if (mRawX >= 0 && mRawX <= mRootMeasuredWidth && mRawY >= mRootTopY && mRawY <= (mRootMeasuredHeight + mRootTopY)) {
//手指X轴滑动距离
float differenceValueX = mRawX - mLastRawX;
//手指Y轴滑动距离
float differenceValueY = mRawY - mLastRawY;
//判断是否为拖动操作
if (!isDrug) {
if (Math.sqrt(differenceValueX * differenceValueX + differenceValueY * differenceValueY) < 2) {
isDrug = false;
} else {
isDrug = true;
}
}
//获取手指按下的距离与控件本身X轴的距离
float ownX = getX();
//获取手指按下的距离与控件本身Y轴的距离
float ownY = getY();
//理论中X轴拖动的距离
float endX = ownX + differenceValueX;
//理论中Y轴拖动的距离
float endY = ownY + differenceValueY;
//X轴可以拖动的最大距离
float maxX = mRootMeasuredWidth - getWidth();
//Y轴可以拖动的最大距离
float maxY = mRootMeasuredHeight - getHeight();
//X轴边界限制
endX = endX < 0 ? 0 : endX > maxX ? maxX : endX;
//Y轴边界限制
endY = endY < 0 ? 0 : endY > maxY ? maxY : endY;
//开始移动
setX(endX);
setY(endY);
//记录位置
mLastRawX = mRawX;
mLastRawY = mRawY;
}
break;
case MotionEvent.ACTION_UP://手指离开
//根据自定义属性判断是否需要贴边
if (customAttachDirect >= 0 && isDrug) {
//判断是否为点击事件 0所有的边 1左 2上 3右 4下 5左右 6上下
float centerX = mRootMeasuredWidth / 2;
float centerY = mRootMeasuredHeight / 2;
float x = -1, y = -1;
if (customAttachDirect == 1) { /*左*/
x = 0;
y = -1;
} else if (customAttachDirect == 2) { /*上*/
x = -1;
y = 0;
} else if (customAttachDirect == 3) { /*右*/
x = mRootMeasuredWidth - getWidth();
y = -1;
} else if (customAttachDirect == 4) {
x = -1;
y = mRootMeasuredWidth - getHeight();
} else if (customAttachDirect == 5) { /*左右*/
x = mLastRawX <= centerX ? 0 : (mRootMeasuredWidth - getWidth());
y = -1;
} else if (customAttachDirect == 6) { /*上下*/
x = -1;
y = mLastRawY <= centerY ? 0 : (mRootMeasuredHeight - getHeight());
} else if (customAttachDirect == 0) { /*距那个边近去那个*/
// TODO: 2020/5/28 0028
}
//自动贴边
ViewPropertyAnimator animator = AttachLayout.this.animate()
.setInterpolator(new BounceInterpolator())
.setDuration(500);
if (x >= 0) {
animator.x(x);
}
if (y >= 0) {
animator.y(y);
}
animator.start();
}
break;
}
}
}
}
网友评论