/**删除原有点击事件, 通过listener注入新的点击事件*/
public class OnDragTouchListener implements View.OnTouchListener {
private int mScreenWidth, mScreenHeight;//屏幕宽高
private float mOriginalX, mOriginalY;//手指按下时的初始位置
private float mDistanceX, mDistanceY;//记录手指与view的左上角的距离
private int left, top, right, bottom;
private OnDraggableClickListener mListener;
private boolean hasAutoPullToBorder;//标记是否开启自动拉到边缘功能
public OnDragTouchListener() {
}
public OnDragTouchListener(boolean isAutoPullToBorder) {
hasAutoPullToBorder = isAutoPullToBorder;
}
@Override
public boolean onTouch(final View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mScreenWidth = v.getResources().getDisplayMetrics().widthPixels;
mScreenHeight = v.getResources().getDisplayMetrics().heightPixels;
mOriginalX = event.getRawX();
mOriginalY = event.getRawY();
mDistanceX = event.getRawX() - v.getLeft();
mDistanceY = event.getRawY() - v.getTop();
break;
case MotionEvent.ACTION_MOVE:
left = (int) (event.getRawX() - mDistanceX);
top = (int) (event.getRawY() - mDistanceY);
right = left + v.getWidth();
bottom = top + v.getHeight();
if (left < 0) {
left = 0;
right = left + v.getWidth();
}
if (top < 0) {
top = 0;
bottom = top + v.getHeight();
}
if (right > mScreenWidth) {
right = mScreenWidth;
left = right - v.getWidth();
}
if (bottom > mScreenHeight) {
bottom = mScreenHeight;
top = bottom - v.getHeight();
}
v.layout(left, top, right, bottom);
break;
case MotionEvent.ACTION_UP:
//如果移动距离过小,则判定为点击
if (mListener != null
&& Math.abs(event.getRawX() - mOriginalX) < 10
&& Math.abs(event.getRawY() - mOriginalY) < 10) {
mListener.onClick(v);
}else {
//在拖动过按钮后,如果其他view刷新导致重绘,会让按钮重回原点,所以需要更改布局参数
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
startAutoPull(v, lp);
}
//消除警告
v.performClick();
break;
}
return true;
}
public OnDraggableClickListener getOnDraggableClickListener() {
return mListener;
}
public void setOnDraggableClickListener(OnDraggableClickListener listener) {
mListener = listener;
}
public boolean isHasAutoPullToBorder() {
return hasAutoPullToBorder;
}
public void setHasAutoPullToBorder(boolean hasAutoPullToBorder) {
this.hasAutoPullToBorder = hasAutoPullToBorder;
}
/**
* 开启自动拖拽
*
* @param v 拉动控件
* @param lp 控件布局参数
*/
private void startAutoPull(final View v, final ViewGroup.MarginLayoutParams lp) {
if (!hasAutoPullToBorder) {
v.layout(left, top, right, bottom);
lp.setMargins(left, top, 0, 0);
v.setLayoutParams(lp);
if (mListener != null) {
mListener.onDragged(v, left, top);
}
return;
}
//当用户拖拽完后,让控件根据远近距离回到最近的边缘
float end = 0;
if ((left + v.getWidth() / 2) >= mScreenWidth / 2) {
end = mScreenWidth - v.getWidth();
}
ValueAnimator animator = ValueAnimator.ofFloat(left, end);
animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(animation -> {
int leftMargin = (int) ((float) animation.getAnimatedValue());
v.layout(leftMargin, top, right, bottom);
lp.setMargins(leftMargin, top, 0, 0);
v.setLayoutParams(lp);
});
final float finalEnd = end;
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
if (mListener != null) {
mListener.onDragged(v, (int) finalEnd, top);
}
}
});
animator.setDuration(400);
animator.start();
}
/**
* 控件拖拽监听器
*/
public interface OnDraggableClickListener {
/**
* 当控件拖拽完后回调
*
* @param v 拖拽控件
* @param left 控件左边距
* @param top 控件右边距
*/
void onDragged(View v, int left, int top);
/**
* 当可拖拽控件被点击时回调
*
* @param v 拖拽控件
*/
void onClick(View v);
}
}
View拖动+点击事件
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 引入 最近在做项目优化的时候,发现点击某个控件使用某个功能时,事先要判断用户是否登录,翻看代码时发现很多地方写了大...
- 需求描述 点击“操作指导”按钮,在其正下方弹出“产品说明书”、“操作视频”两个选项供用户选择,点击PopupWin...
- 实现想法 很简单View消费自己点击事件是要触发onTouchEvent方法,只需要自定义一下View,并重写on...