Android自定义ViewAndroid 自定义控件

拖拽控件

2020-06-07  本文已影响0人  我的阿福
case MotionEvent.ACTION_DOWN:
                mLastTouchX = event.getRawX();//这里要注意,不能用getX,后面有解释
                mLastTouchY = event.getRawY();

 case MotionEvent.ACTION_MOVE:
                float nowX = event.getRawX();
                float nowY = event.getRawY();
                float delX = nowX - mLastTouchX;//x方向滑动距离
                float delY = nowY - mLastTouchY;//y方向滑动距离
 float tranY = getTranslationY() + delY;
                float nowReY = getY();
              //这几句判断是为了不让自己垂直方向超出父视图的边界
                if (nowReY <= 0 && delY < 0) {
                    tranY = -getTop();
                } else if (nowReY + mHeight >= mParentHeight && delY > 0) {
                    tranY = mParentHeight - mHeight - getTop();
                }
                float tranX = getTranslationX() + delX;
                float nowReX = getX();
                //同理,不让自己水平方向超出父视图的边界
                if (nowReX <= 0 && delX < 0) {
                    tranX = -getLeft();
                } else if (nowReX + mWidth >= mParentWidth && delX > 0) {
                    tranX = mParentWidth - getRight();
                }

                setTranslationX(tranX);
                setTranslationY(tranY);
if (getX() + (mWidth / 2) > (mParentWidth / 2)) {
            int rightMoveDistance = (int) (mParentWidth - getX() - mWidth / 2);
            //貼右边
            startSideAnimation(RIGTHSIDE, getTranslationX(), rightMoveDistance);
        } else {
            //貼左边
            int leftMoveDistance = (int) (getX() + mWidth / 2);
            startSideAnimation(LEFTSIDE, getTranslationX(), leftMoveDistance);
        } 
private void startSideAnimation(final int side, final float origTX, int moveDistance) {
        mSideAnimation = ValueAnimator.ofFloat(moveDistance);
        mSideAnimation.setDuration(200);
        mSideAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        mSideAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                switch (side) {
                    case LEFTSIDE:
                        setTranslationX(origTX - value);
                        break;
                    default:
                        setTranslationX(origTX + value);
                }
            }
        });
        mSideAnimation.start();
    } 

整个过程其实很简单,但值得注意的地方有两个:
1.获取手指位置用的getRawX而不是getX,这两个的区别:getRawX是手指接触view的位置距离整个屏幕边界的距离,getX是手指触摸view的位置距离父布局边界的距离。如果这里用getX的话,当view移动的时候,getX也会相应改变,无法达到想要的效果。
2.移动view的位置,直接用setTranslationX,setTranslationY的方法。

package com.anthony.widgets;

import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.animation.AccelerateDecelerateInterpolator;

/**
 * Created by H.Anthony on 2020/06/06.
 */
public class MoveSpirit extends View {

    private static final String TAG = "MoveSpirit";
    private static final int LEFTSIDE = 0x1;
    private static final int RIGTHSIDE = 0x2;
    private float mLastTouchX, mLastTouchY;
    private int mParentWidth, mParentHeight, mWidth, mHeight;
    private ValueAnimator mSideAnimation;

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

    public MoveSpirit(Context context, @androidx.annotation.Nullable AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        ViewParent viewParent = getParent();
        if (viewParent != null) {
            if (viewParent instanceof ViewGroup) {
                ViewGroup viewGroup = (ViewGroup) viewParent;
                mParentWidth = viewGroup.getWidth();
                mParentHeight = viewGroup.getHeight();
                mWidth = getWidth();
                mHeight = getHeight();
                Log.d(TAG, "onSizeChanged: " + mParentWidth + ";" + mParentHeight + ";" + mWidth + ";" + mHeight);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        closeAnimation();
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastTouchX = event.getRawX();
                mLastTouchY = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                float nowX = event.getRawX();
                float nowY = event.getRawY();
                float delX = nowX - mLastTouchX;
                float delY = nowY - mLastTouchY;

                float tranY = getTranslationY() + delY;
                float nowReY = getY();
                if (nowReY <= 0 && delY < 0) {
                    tranY = -getTop();
                } else if (nowReY + mHeight >= mParentHeight && delY > 0) {
                    tranY = mParentHeight - mHeight - getTop();
                }
                float tranX = getTranslationX() + delX;
                float nowReX = getX();
                if (nowReX <= 0 && delX < 0) {
                    tranX = -getLeft();
                } else if (nowReX + mWidth >= mParentWidth && delX > 0) {
                    tranX = mParentWidth - getRight();
                }

                setTranslationX(tranX);
                setTranslationY(tranY);

                mLastTouchX = nowX;
                mLastTouchY = nowY;
                break;
            case MotionEvent.ACTION_UP:
                autoTouchSide();
                break;
        }

        return true;
    }


    /**
     * 左右動畫
     */
    private void autoTouchSide() {
        if (getX() + (mWidth / 2) > (mParentWidth / 2)) {
            int rightMoveDistance = (int) (mParentWidth - getX() - mWidth / 2);
            //貼右边
            startSideAnimation(RIGTHSIDE, getTranslationX(), rightMoveDistance);
        } else {
            //貼左边
            int leftMoveDistance = (int) (getX() + mWidth / 2);
            startSideAnimation(LEFTSIDE, getTranslationX(), leftMoveDistance);
        }

    }

    private void startSideAnimation(final int side, final float origTX, int moveDistance) {
        mSideAnimation = ValueAnimator.ofFloat(moveDistance);
        mSideAnimation.setDuration(200);
        mSideAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
        mSideAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (float) animation.getAnimatedValue();
                switch (side) {
                    case LEFTSIDE:
                        setTranslationX(origTX - value);
                        break;
                    default:
                        setTranslationX(origTX + value);
                }
            }
        });
        mSideAnimation.start();
    }

    private void closeAnimation() {
        if (mSideAnimation != null && mSideAnimation.isRunning()) {
            mSideAnimation.removeAllUpdateListeners();
            mSideAnimation.cancel();
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.anthony.widgets.MoveSpirit
        android:layout_width="160dp"
        android:layout_height="160dp"
        android:background="@mipmap/panda"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
上一篇下一篇

猜你喜欢

热点阅读