java按压拖动窗体事件,安卓实现任意控件view可拖拽,并监听拖拽和点击事件,可自动拉回屏幕边缘...

因为项目中有需要实现控件可任意拖拽的需求,所以简单写了个自定义OnTouchListener,以作抛砖引玉,欢迎大家提议反馈。

完整实现类如下,代码中有详细注释: 用户可以决定是否开启自动拖拽边缘功能,可以监听控件的拖拽和点击事件

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:

//在拖动过按钮后,如果其他view刷新导致重绘,会让按钮重回原点,所以需要更改布局参数

ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();

startAutoPull(v, lp);

if (mListener != null) {

mListener.onDragged(left, top);

}

//如果移动距离过小,则判定为点击

if (Math.abs(event.getRawX() - mOriginalX) <

ScreenUtils.getPxFromDp(v.getResources(), 5) &&

Math.abs(event.getRawY() - mOriginalY) <

ScreenUtils.getPxFromDp(v.getResources(), 5)) {

if (mListener != null) {

mListener.onClick();

}

}

//消除警告

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) {

lp.setMargins(left, top, 0, 0);

v.setLayoutParams(lp);

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(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

lp.setMargins((int) ((float) animation.getAnimatedValue()), top, 0, 0);

v.setLayoutParams(lp);

}

});

animator.setDuration(400);

animator.start();

}

/**

* 可拖拽控件被点击时回调

*/

public interface OnDraggableClickListener {

/**

* 当控件拖拽完后回调

*

* @param left 控件左边距

* @param top 控件右边距

*/

void onDragged(int left, int top);

/**

* 当可拖拽控件被点击时回调

*/

void onClick();

}

}

后期有时间会做更多优化和扩展功能,如果有什么更好的方式或建议,欢迎大家反馈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值