Android自定義OnTouch事件

花椒CX發表於2018-06-25

自定義View的onTouch

在專案開發的過程中,使用到了ImageView控制元件,要做選中狀態,很自然的想到了selector方式,可就是這麼一個簡單的東西,足足折騰了我兩三個小時。

問題

  1. selector選中狀態莫名失效,對此網上有些對應的解決方法是,將selector中true的狀態放在第一位置;
  2. 我想做longclick或者doubleclick都很麻煩
  3. imageview無法響應onTouch事件,必須要先在xml中設定clickable = true,或者 return true ,但即便是這樣,也難以獲取cancel事件。

人的生命是有限的,不想把太多時間浪費在上面莫名其妙的問題上,所以,擼起袖子自己幹,寫了一個簡單的onTouch封裝類。

程式碼如下:

public class HJCXOnTouchListener implements View.OnTouchListener {

    private final int longTime = 1000;//長按事件定為1000ms
    private boolean isUpOut = false;//是否是在控制元件之外抬起
    private boolean hasResponseLongClickEvent = false;//是否響應了長按事件
    private OnHJCXOnTouchListener onHJCXOnTouchListener;
    private long clickTime = 0;

    public HJCXOnTouchListener(OnHJCXOnTouchListener onHJCXOnTouchListener) {
        this.onHJCXOnTouchListener = onHJCXOnTouchListener;
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        float x = event.getRawX();
        float y = event.getRawY();
        if (event.getAction() == MotionEvent.ACTION_DOWN){
            clickTime = System.currentTimeMillis();
            isUpOut = false;
            hasResponseLongClickEvent = false;
            onHJCXOnTouchListener.onHJCXOnTouchListener(OnHJCXOnTouchListener.CLICK);
        }
        if (event.getAction() == MotionEvent.ACTION_MOVE){
            if (isInside(v,x,y)){
                isUpOut = false;
            }else{
                isUpOut = true;
            }
            if (System.currentTimeMillis() - clickTime > longTime  && !hasResponseLongClickEvent  && !isUpOut){
                hasResponseLongClickEvent = true;
                onHJCXOnTouchListener.onHJCXOnTouchListener(OnHJCXOnTouchListener.LONG_CLICK);
            }
        }
        if (event.getAction() == MotionEvent.ACTION_UP){
            if (isUpOut){
                onHJCXOnTouchListener.onHJCXOnTouchListener(OnHJCXOnTouchListener.CANCEL);
            }else{
                if (!hasResponseLongClickEvent)//longclick響應後,不再響應UP事件
                    onHJCXOnTouchListener.onHJCXOnTouchListener(OnHJCXOnTouchListener.UP);
            }
        }

        return true;
    }

    boolean isInside(View view, float x, float y) {
        if (view == null) {
            return false;
        }
        //獲取控制元件在螢幕的位置
        int[] location = new int[2];
        view.getLocationOnScreen(location);

        //控制元件相對於螢幕的x與y座標
        int xScreen = location[0];
        int yScreen = location[1];
        Rect rect = new Rect(xScreen,
                yScreen,
                xScreen + view.getWidth(),
                yScreen + view.getHeight());
        return rect.contains((int) x, (int) y);
    }

    public interface OnHJCXOnTouchListener{
        //點選
        int CLICK = 0;

        //抬起
        int UP = 1;

        //長按
        int LONG_CLICK = 2;

        //取消
        int CANCEL = 3;

        void onHJCXOnTouchListener(int type);
    }

如上,用的都是一些基本的方法,比較生僻的方法估計就是isInside方法了,用於判斷cancel事件(手指移出控制元件範圍)。

呼叫方式如下

view.setOnTouchListener(new HJCXOnTouchListener(new HJCXOnTouchListener.OnHJCXOnTouchListener() {
            @Override
            public void onHJCXOnTouchListener(int type) {
                switch (type){
                    case HJCXOnTouchListener.OnHJCXOnTouchListener.CLICK:
                        //
                        break;
                    case HJCXOnTouchListener.OnHJCXOnTouchListener.UP:
                        //
                        break;
                    case HJCXOnTouchListener.OnHJCXOnTouchListener.LONG_CLICK:
                        //
                        break;
                    case HJCXOnTouchListener.OnHJCXOnTouchListener.CANCEL:
                        //
                        break;
                }
            }
        }));

好了,以上就是我的這次自定義OnTouch事件,如有不足之處,還望多多指教。

相關文章