Android支持点击的TouchView(可拖动视图)

需求:

1、一个可以拖动的view;

2、该view可以通过setOnClickListener设置点击监听。

解决思路:

可拖动视图就必须重写onTouch事件,但是重写onTouch事件,点击事件肯定会被过滤。所以,需要我们自己再处理一下,把符合条件的onTouch事件转化成点击事件。

需求和解决思路都出来了,那代码就很好实现了,我们先来看一下效果图。

Android支持点击的TouchView(可拖动视图)_第1张图片


上最主要的代码:(一会还有DEMO)

package com.milo.widget;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

/**
 * 支持点击事件的可拖动视图
 * The view can touch and support click event
 *
 * @author Milo
 *         Email:[email protected]
 * @version 2018/4/20
 */
public class TouchView extends View {
    private static final String TAG = "TouchView";

    /**
     * 记录X轴最后位置
     */
    int lastX = 0;
    /**
     * 记录Y轴最后位置
     */
    int lastY = 0;
    /**
     * 记录Action_Down - X轴位置
     */
    int downX = 0;
    /**
     * 记录Action_Down - Y轴位置
     */
    int downY = 0;
    /**
     * 记录Action_Down 时间
     */
    long lastDownInMills;

    final int DEFAULT_LIMITLEFT = 0;
    final int DEFAULT_LIMITTOP = 0;

    int limitLeft;
    int limitTop;
    int limitRight;
    int limitBottom;

    int screenWidth;
    int screenHeight;

    private OnClickListener l;

    public TouchView(Context context) {
        super(context);
    }

    public TouchView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        screenWidth = metrics.widthPixels;
        screenHeight = metrics.heightPixels;
        setLimitAuto();
    }

    public TouchView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 自适应边界
     */
    private void setLimitAuto() {
        setLimitAuto(null);
    }

    /**
     * 根据parentView自适应边界
     *
     * @param parentView
     */
    public void setLimitAuto(ViewGroup parentView) {
        if (parentView == null) {
            this.limitLeft = DEFAULT_LIMITLEFT;
            this.limitTop = DEFAULT_LIMITTOP;
            this.limitRight = screenWidth;
            this.limitBottom = screenHeight;
        } else {
            this.limitLeft = parentView.getLeft();
            this.limitTop = parentView.getTop();
            this.limitRight = parentView.getRight();
            this.limitBottom = parentView.getBottom();
        }
    }

    /**
     * 设定自定义边界
     *
     * @param limitLeft
     * @param limitTop
     * @param limitRight
     * @param limitBottom
     */
    public void setLimitParams(int limitLeft, int limitTop, int limitRight, int limitBottom) {
        this.limitLeft = limitLeft;
        this.limitTop = limitTop;
        this.limitRight = limitRight;
        this.limitBottom = limitBottom;
    }

    @Override
    public void setOnClickListener(@Nullable OnClickListener l) {
        this.l = l;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //TODO 按下瞬间记录所有信息
                lastDownInMills = System.currentTimeMillis();
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                downX = (int) event.getRawX();
                downY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //TODO 计算相对位置
                int dx = (int) event.getRawX() - lastX;
                int dy = (int) event.getRawY() - lastY;
                int left = getLeft() + dx;
                int top = getTop() + dy;
                int right = getRight() + dx;
                int bottom = getBottom() + dy;

                //TODO 限制边界
                if (left < limitLeft) {
                    left = limitLeft;
                    right = left + getWidth();
                }
                if (top < limitTop) {
                    top = limitTop;
                    bottom = top + getHeight();
                }
                if (right > limitRight) {
                    right = limitRight;
                    left = limitRight - getWidth();
                }
                if (bottom > limitBottom) {
                    bottom = limitBottom;
                    top = limitBottom - getHeight();
                }

                //TODO 更新view的位置
                layout(left, top, right, bottom);
                lastX = (int) event.getRawX();
                lastY = (int) event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                dx = (int) event.getRawX() - downX;
                dy = (int) event.getRawY() - downY;
                if (dx + dy == 0 && System.currentTimeMillis() - lastDownInMills < 500) {
                    //TODO x + y移动距离小于2px 且 触碰时间小于500ms 触发点击事件
                    if (l != null) {
                        l.onClick(this);
                    }
                }
                break;
        }
        return true;
    }

}

源码下载地址(如果没有积分的,可以直接邮件[email protected]向我要):

https://download.csdn.net/download/yanjunhui2011/10365148

顺便吐槽一下CDSN近期的改动,设置密码复杂度要求过高,微信登录无法绑定已有账号。我这篇博文就是刚在微信那个账号下登录的,结果写完一看,咋就只有一篇呢?

还有下载,以前免积分的,全部默认3积分,且无法修改,我个人积分够用,我不希望那些需要我资源的用户因为积分无法下载,这严重违背了开源精神。

我觉得CSDN再长久这么玩下去,就是在自掘坟墓。

国内这种平台还有很多,此文不过,必跳简书。


你可能感兴趣的:(个人)