Android

Android 自定義拖移的View

1.先創建一個類繼承你想要的View並實現前三個構造方法

public class DragFloatActionButton extends androidx.appcompat.widget.AppCompatImageView {

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

    public DragFloatActionButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

2.複寫觸控方法

@SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return true;
    }

3.取得觸碰的X,Y座標

int rawX = (int) event.getRawX();
int rawY = (int) event.getRawY();

4.判斷 按下,移動,抬起三種操作模式

switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                Log.d("event", "ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.d("event", "ACTION_MOV");
                break;
            case MotionEvent.ACTION_UP:
                Log.d("event", "ACTION_UP");
                break;
        }

5.按下動作(ACTION_DOWN)

  //取得按下時間
  startTime = System.currentTimeMillis();
  //不要讓父控件攔截事件
  getParent().requestDisallowInterceptTouchEvent(true);
  lastX = rawX;
  lastY = rawY;

  if (getParent() != null) {
  //取得父控件的寬高
  ViewGroup parent = (ViewGroup) getParent();
  parentHeight = parent.getHeight();
  parentWidth = parent.getWidth();

6.移動事件(ACTION_MOVE)

//移動座標-最後一次座標
int dx = rawX - lastX;
int dy = rawY - lastY;

float x = getX() + dx;
float y = getY() + dy;

x = x < 0 ? 0 : x > parentWidth - getWidth() ? parentWidth - getWidth() : x;
y = getY() < 0 ? 0 : getY() + getHeight() > parentHeight ? parentHeight - getHeight() : y;
setX(x);
setY(y);
lastX = rawX;
lastY = rawY;

7.抬起事件(ACTION_UP)

//取得最後抬起時間
long endTime = System.currentTimeMillis();
if (endTime - startTime < 100) {
      Log.d("event", "點擊");
      //觸發點擊事件
      performClick();
} else {
      Log.d("event", "拖移");
}

if (rawX >= parentWidth / 2) {
  //靠右吸附
   animate().setInterpolator(new DecelerateInterpolator())
            .setDuration(500)
            .xBy(parentWidth - getWidth() - getX())
            .start();
} else {
   //靠左吸附
   ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
   oa.setInterpolator(new DecelerateInterpolator());
   oa.setDuration(500);
}

8.完整程式碼

import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;

import androidx.annotation.Nullable;

public class DragFloatActionButton extends androidx.appcompat.widget.AppCompatImageView {

    private long startTime;
    private int lastX;
    private int lastY;
    private int parentHeight;
    private int parentWidth;

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

    public DragFloatActionButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int rawX = (int) event.getRawX();
        int rawY = (int) event.getRawY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startTime = System.currentTimeMillis();
                //不要讓父控件攔截事件
                getParent().requestDisallowInterceptTouchEvent(true);
                lastX = rawX;
                lastY = rawY;

                if (getParent() != null) {
                    //取得父控件的寬高
                    ViewGroup parent = (ViewGroup) getParent();
                    parentHeight = parent.getHeight();
                    parentWidth = parent.getWidth();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                //移動座標-最後一次座標
                int dx = rawX - lastX;
                int dy = rawY - lastY;

                float x = getX() + dx;
                float y = getY() + dy;

                x = x < 0 ? 0 : x > parentWidth - getWidth() ? parentWidth - getWidth() : x;
                y = getY() < 0 ? 0 : getY() + getHeight() > parentHeight ? parentHeight - getHeight() : y;
                setX(x);
                setY(y);
                lastX = rawX;
                lastY = rawY;
                break;
            case MotionEvent.ACTION_UP:
                long endTime = System.currentTimeMillis();

                if (endTime - startTime < 100) {
                    Log.d("event", "點擊");
                    performClick();
                } else {
                    Log.d("event", "拖移");
                }

                if (rawX >= parentWidth / 2) {
                    //靠右吸附
                    animate().setInterpolator(new DecelerateInterpolator())
                            .setDuration(500)
                            .xBy(parentWidth - getWidth() - getX())
                            .start();
                } else {
                    //靠左吸附
                    ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
                    oa.setInterpolator(new DecelerateInterpolator());
                    oa.setDuration(500);
                    oa.start();
                }
                break;
        }
        return true;
    }
}

發表迴響