Android 拖动任意View代码

记得之前项目里面,写过这种需求,不过跟项目耦合的紧,又重网上找了几篇文章看了下,顺便也抄了下其他作者写的代码,如果需求场景比较简单,只是为了在当前手机屏幕里面拖动view,那么可以直接用本篇文章的代码,这里呢,有两个类,一个是自定义的ImageView,用于ImageView的任意拖拽效果,还有一个是fabButton的,可以任意拖拽fabButton。

代码比较简单,下次有类似简单需求,就可以直接抄代码了,不然还得找半天。我们先看ImageView的.

@SuppressLint("AppCompatCustomView")
public class DragImageView extends ImageView {

    private int width;
    private int height;
    private int screenWidth;
    private int screenHeight;
    private Context context;

    //是否拖动
    private boolean isDrag = false;
    private float downX;
    private float downY;


    public DragImageView(Context context) {
        super(context);
        this.context = context;
    }

    public DragImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public boolean isDrag() {
        return isDrag;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
        screenWidth = SystemUtils.getWindowWidth();
        screenHeight = SystemUtils.getWindowHeight() - SystemUtils.getStatusBarHeight();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        if (this.isEnabled()) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    isDrag = false;
                    downX = event.getX();
                    downY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    final float xDistance = event.getX() - downX;
                    final float yDistance = event.getY() - downY;
                    int l, r, t, b;
                    //当水平或者垂直滑动距离大于10,才算拖动事件
                    if (Math.abs(xDistance) > 10 || Math.abs(yDistance) > 10) {
                        isDrag = true;
                        l = (int) (getLeft() + xDistance);
                        r = l + width;
                        t = (int) (getTop() + yDistance);
                        b = t + height;
                        //不划出边界判断,此处应按照项目实际情况,因为本项目需求移动的位置是手机全屏,
                        // 所以才能这么写,如果是固定区域,要得到父控件的宽高位置后再做处理
                        if (l < 0) {
                            l = 0;
                            r = l + width;
                        } else if (r > screenWidth) {
                            r = screenWidth;
                            l = r - width;
                        }
                        if (t < 0) {
                            t = 0;
                            b = t + height;
                        } else if (b > screenHeight) {
                            b = screenHeight;
                            t = b - height;
                        }

                        this.layout(l, t, r, b);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    setPressed(false);
                    break;
                case MotionEvent.ACTION_CANCEL:
                    setPressed(false);
                    break;
            }
            return true;
        }
        return false;
    }

}

 

接着在看看FabButton的吧,其实代码是差不多的

public class DragFloatingActionButton extends FloatingActionButton {

    private int width;
    private int height;
    private int screenWidth;
    private int screenHeight;
    private Context context;

    //是否拖动
    private boolean isDrag = false;
    private float downX;
    private float downY;


    public DragFloatingActionButton(Context context) {
        super(context);
        this.context = context;
    }

    public DragFloatingActionButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public boolean isDrag() {
        return isDrag;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getMeasuredWidth();
        height = getMeasuredHeight();
        screenWidth = SystemUtils.getWindowWidth();
        screenHeight = SystemUtils.getWindowHeight() - SystemUtils.getStatusBarHeight();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        if (this.isEnabled()) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    isDrag = false;
                    downX = event.getX();
                    downY = event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    final float xDistance = event.getX() - downX;
                    final float yDistance = event.getY() - downY;
                    int l, r, t, b;
                    //当水平或者垂直滑动距离大于10,才算拖动事件
                    if (Math.abs(xDistance) > 10 || Math.abs(yDistance) > 10) {
                        isDrag = true;
                        l = (int) (getLeft() + xDistance);
                        r = l + width;
                        t = (int) (getTop() + yDistance);
                        b = t + height;
                        //不划出边界判断,此处应按照项目实际情况,因为本项目需求移动的位置是手机全屏,
                        // 所以才能这么写,如果是固定区域,要得到父控件的宽高位置后再做处理
                        if (l < 0) {
                            l = 0;
                            r = l + width;
                        } else if (r > screenWidth) {
                            r = screenWidth;
                            l = r - width;
                        }
                        if (t < 0) {
                            t = 0;
                            b = t + height;
                        } else if (b > screenHeight) {
                            b = screenHeight;
                            t = b - height;
                        }

                        this.layout(l, t, r, b);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    setPressed(false);
                    break;
                case MotionEvent.ACTION_CANCEL:
                    setPressed(false);
                    break;
            }
            return true;
        }
        return false;
    }

}

核心逻辑是在onTouchEvent里面的判断。有需要研究的可以自己分析。

 

如果view需要处理点击事件呢。

那么代码上的用法需要注意下,参考如下的姿势:

dragView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("TEST", "onClick() dragView 111");
                if (dragView.isDrag()) {
                    return;
                }
                Log.e("TEST", "onClick() dragView 222");
                Toast.makeText(MainActivity.this, "哈哈", Toast.LENGTH_SHORT).show();
            }
        });

 

写这篇是为了记录,像这种不经常写的代码(需求场景简单的),放个地方托管,方便下次复制粘贴。

 

Android 拖动任意View代码

上一篇:vue移动端touch插件


下一篇:ObjectMapper类