美文网首页Android自定义View
Android 自定义拖拽、吸边控件简单实现

Android 自定义拖拽、吸边控件简单实现

作者: 可乐_JS | 来源:发表于2021-01-06 17:49 被阅读0次

    第二次做拖拽吸边的功能了,但还是费了不少时间,所以简单记录下!

    拖拽、吸边.gif
    1.参数:
        <declare-styleable name="MoveFrameLayout">
            <!--是否需要自动吸边-->
            <attr name="IsAttach" format="boolean" />
            <!--是否可拖曳-->
            <attr name="IsDrag" format="boolean" />
        </declare-styleable>
    
    2.代码:
    package 包名.weight;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Rect;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.OvershootInterpolator;
    import android.widget.FrameLayout;
    
    import com.blankj.utilcode.util.SizeUtils;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    import 包名.R;
    
    /**
     * Des: 拖拽、自吸边控件
     * Created by kele on 2021/1/6.
     * E-mail:984127585@qq.com
     */
    public class MoveFrameLayout extends FrameLayout {
    
        public MoveFrameLayout(@NonNull Context context) {
            this(context, null);
        }
    
        public MoveFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public MoveFrameLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initAttrs(context, attrs);
        }
    
        private boolean isAttach;//是否自动吸边
        private boolean isDrag;//是否可拖动
    
        /**
         * 初始化自定义属性
         */
        private void initAttrs(Context context, AttributeSet attrs) {
            TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.MoveFrameLayout);
            isAttach = mTypedAttay.getBoolean(R.styleable.MoveFrameLayout_IsAttach, true);
            isDrag = mTypedAttay.getBoolean(R.styleable.MoveFrameLayout_IsDrag, true);
            mTypedAttay.recycle();
        }
    
        private int mParentWidth = 0;//父控件的宽
        private int mParentHeight = 0;//父控件的高
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            //获取父控件宽高
            ViewGroup mViewGroup = (ViewGroup) getParent();
            if (mViewGroup != null) {
                int[] location = new int[2];
                mViewGroup.getLocationOnScreen(location);
                //获取父布局的高度
                mParentHeight = mViewGroup.getMeasuredHeight();
                mParentWidth = mViewGroup.getMeasuredWidth();
            }
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            //点击点在控件区域内,接受事件
            boolean inRangeOfView = inRangeOfView(this, ev);
            return inRangeOfView;
        }
    
        private float mLastX;//按下位置x
        private float mLastY;//按下位置Y
        private boolean isDrug = false;//是否是拖动
    
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            if (isDrag) {
                //请求父控件将事件交由自己处理
                getParent().requestDisallowInterceptTouchEvent(true);
                float mX = ev.getX();
                float mY = ev.getY();
                switch (ev.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //重置拖动状态
                        isDrug = false;
                        //记录按下的位置
                        mLastX = mX;
                        mLastY = mY;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //手指X轴滑动距离
                        float differenceValueX = mX - mLastX;
                        //手指Y轴滑动距离
                        float differenceValueY = mY - mLastY;
                        //判断是否为拖动操作
                        if (!isDrug) {
                            if (Math.sqrt(differenceValueX * differenceValueX + differenceValueY * differenceValueY) < 2) {
                                isDrug = false;
                            } else {
                                isDrug = true;
                            }
                        }
                        //获取手指按下的距离与控件本身X轴的距离
                        float ownX = getX();
                        //获取手指按下的距离与控件本身Y轴的距离
                        float ownY = getY();
                        //理论中X轴拖动的距离
                        float endX = ownX + differenceValueX;
                        //理论中Y轴拖动的距离
                        float endY = ownY + differenceValueY;
                        //X轴可以拖动的最大距离
                        float maxX = mParentWidth - getWidth();
                        //Y轴可以拖动的最大距离
                        float maxY = mParentHeight - getHeight() - SizeUtils.dp2px(getPaddingBottom() + 15);
                        //X轴边界限制---这里对X轴拖动不做限制
                        //endX = endX < 0 ? 0 : endX > maxX ? maxX : endX;
                        //Y轴边界限制
                        endY = endY < 0 ? 0 : endY > maxY ? maxY : endY;
                        //开始移动
                        setX(endX);
                        setY(endY);
                        break;
                    case MotionEvent.ACTION_UP:
                        //根据自定义属性判断是否需要贴边
                        if (isAttach) {
                            //判断是否为点击事件
                            float center = mParentWidth / 2;
                            //自动贴边
                            if (ev.getRawX() <= center) {
                                //向左贴边
                                animate()
                                        //.setInterpolator(new BounceInterpolator())
                                        .setInterpolator(new OvershootInterpolator())
                                        .setDuration(400)
                                        .x(SizeUtils.dp2px(0))
                                        .start();
                            } else {
                                //向右贴边
                                animate()
                                        .setInterpolator(new OvershootInterpolator())
                                        .setDuration(400)
                                        .x(mParentWidth - getWidth() - SizeUtils.dp2px(0))
                                        .start();
                            }
                        }
                        break;
                }
            }
            return isDrug ? true : super.onTouchEvent(ev);
        }
    
        /**
         * 点击点是否在控件区域
         *
         * @param view
         * @param ev
         * @return
         */
        private boolean inRangeOfView(View view, MotionEvent ev) {
            Rect rect = new Rect();
            view.getGlobalVisibleRect(rect);
            int rawX = (int) ev.getRawX();
            int rawY = (int) ev.getRawY();
            if (rect.contains(rawX, rawY)) {
                return true;
            }
            return false;
        }
    }
    
    3.使用:
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:paddingBottom="@dimen/dp_50"
        android:layout_height="match_parent">
    
        <包名.weight.MoveFrameLayout
            android:id="@+id/mfl_fb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|right"
            app:IsAttach="true"
            app:IsDrag="true"
            android:layout_marginBottom="@dimen/dp_50"
            android:padding="@dimen/dp_12">
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_fb" />
        </包名.weight.MoveFrameLayout>
    </FrameLayout>
    

    相关文章

      网友评论

        本文标题:Android 自定义拖拽、吸边控件简单实现

        本文链接:https://www.haomeiwen.com/subject/kihooktx.html