使用ViewDragHelper 实现吸边效果

由于项目需求需要按钮吸边,就自己动手写了下。对于通过手势拖拽我立马就想到了ViewDragHelper这个系统工具类。有了这个类的存在 我们只需要处理松开手指的逻辑处理和边界控制就行了。
下面是实现代码

public class SuctionSideView extends RelativeLayout {

    private final String TAG = "SuctionSideView";
    private ViewDragHelper mDragHelper; // 拖拽控制
    private View mSuctionView; // 要吸边的view
    private Point mAutoBackOriginPos = new Point(); // 记录子view现在的位置
    private boolean isInit = false;

    /**
     * 1 | 2
     * -----
     * 3 | 4
     */
    private int centerX;// 屏幕中心的x值
    private int centerY;// 屏幕中心的y值 根据这两个属性建立直角坐标系

    public SuctionSideView(@NonNull Context context) {
        super(context,null);
    }

    public SuctionSideView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
        addListener();
    }

    /**
     * 初始化布局
     * @throws Exception
     */
    private void init() {

    }

    /**
     * 监听事件注册
     */
    private void addListener() {
        mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mSuctionView;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                final int leftBound = getPaddingLeft() + UIUtil.dp2px(10);
                final int rightBound = getWidth() - child.getWidth() - leftBound  - UIUtil.dp2px(10);
                final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
                return newLeft;
            }

            @Override
            public int getViewHorizontalDragRange(View child) {
                return getMeasuredWidth() - child.getMeasuredWidth();
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                final int topBound = getPaddingTop()  + UIUtil.dp2px(10);
                final int bottomBound = getHeight() - child.getHeight() - getPaddingBottom() - UIUtil.dp2px(10);
                final int newTop = Math.min(Math.max(top,topBound),bottomBound);
                return newTop;
            }

            @Override
            public int getViewVerticalDragRange(View child) {
                return getMeasuredHeight() - child.getMeasuredHeight();
            }

            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                if (releasedChild == mSuctionView) {
                    if (releasedChild.getLeft() < centerX) { // 往左移动
                        moveTo(UIUtil.dp2px(10) + getPaddingLeft(), releasedChild.getTop());
                    } else { // 往右
                        moveTo(getWidth() - UIUtil.dp2px(59) - getPaddingRight(), releasedChild.getTop());
                    }
//                    if (releasedChild.getLeft() < centerX && releasedChild.getTop() < centerY) { // 1象限
//                        if (releasedChild.getLeft() < releasedChild.getTop()) { // 往左
//                            moveTo(0, releasedChild.getTop());
//                        } else { // 网上
//                            moveTo(releasedChild.getLeft(), 0);
//                        }
//                    } else if (releasedChild.getLeft() > centerX && releasedChild.getTop() < centerY) { // 2象限
//                        if (getWidth() - releasedChild.getLeft() - getWidth() < getTop() - releasedChild.getHeight()) { // 往右
//                            moveTo(getWidth() - releasedChild.getWidth() - getPaddingRight(), releasedChild.getTop());
//                        } else { // 往上
//                            moveTo(releasedChild.getLeft(), 0);
//                        }
//                    } else if (releasedChild.getLeft() < centerX && releasedChild.getTop() > centerY) { // 3 象限
//                        if (releasedChild.getLeft() < getHeight() - releasedChild.getTop() - releasedChild.getHeight()) { // 往左
//                            moveTo(0, releasedChild.getTop());
//                        } else { // 往下
//                            moveTo(releasedChild.getLeft(), getHeight() - releasedChild.getHeight() - getPaddingBottom());
//                        }
//                    } else if (releasedChild.getLeft() > centerX && releasedChild.getTop() > centerY) { // 4象限
//                        if (getWidth() - releasedChild.getLeft() - releasedChild.getWidth() < getHeight() - releasedChild.getTop() - releasedChild.getHeight()) { // 向右
//                            moveTo(getWidth() - releasedChild.getWidth() - getPaddingRight(), releasedChild.getTop());
//                        } else { // 往下
//                            moveTo(releasedChild.getLeft(), getHeight() - releasedChild.getHeight() - getPaddingBottom());
//                        }
//
//                    }
                    ViewCompat.postInvalidateOnAnimation(SuctionSideView.this);
                }
            }
        });
    }

    private void moveTo(int xvel, int yvel) {
        mAutoBackOriginPos.x = xvel;
        mAutoBackOriginPos.y = yvel;
        mDragHelper.smoothSlideViewTo(mSuctionView,xvel,yvel);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mSuctionView = getChildAt(0);
        LogUtil.i(TAG,"onFinishInflate");
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;
        if (!isInit) {
            mAutoBackOriginPos.x = getWidth() - UIUtil.dp2px(59);
            mAutoBackOriginPos.y = getHeight() - UIUtil.dp2px(75);
            isInit = true;
            mSuctionView.layout(mAutoBackOriginPos.x,mAutoBackOriginPos.y,mAutoBackOriginPos.x + UIUtil.dp2px(49),mAutoBackOriginPos.y + UIUtil.dp2px(65));
            LogUtil.i(TAG,"mAutoBackOriginPos.x:" + mAutoBackOriginPos.x + "mAutoBackOriginPos.y" + mAutoBackOriginPos.y);
        }

    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragHelper.processTouchEvent(event);
        return false;
    }

    @Override
    public void computeScroll() {
        if (mDragHelper.continueSettling(true)) {
            invalidate();
        }
    }
}

这里面记录下吸边控件的初始位置。

clampViewPositionHorizontal与clampViewPositionVertical
这是控制吸边控件的上下左右能够活动位置

由于我的项目中值需要左右吸边所以我在

onViewReleased 里只需要判断当前控件的left超过中心线了没

其中涉及到的数字为吸边控件距左距右和控件本身的尺寸,整个代码差不多100行是不是很简单吧。
使用也非常简单 用自定义好的控件包裹住需要被吸边的控件

<cn.lhj.home.widget.SuctionSideView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/title_bar">

        <ImageView
            android:id="@+id/view"
            android:layout_width="49dp"
            android:layout_height="65dp"
            android:layout_gravity="right|bottom"
            android:layout_marginBottom="10dp"
            android:layout_marginRight="10dp"
            android:scaleType="fitXY"
            android:visibility="gone" />
    </cn.lhj.home.widget.SuctionSideView>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值