悬浮View,可拖动,放手后自动吸附到屏幕边上。

悬浮View,应用内悬浮

本章给大家介绍自定义悬浮View,可随手指拖动,手指放开后会自动吸附到手机屏边缘,悬浮View内的Content布局可以任意放入自定义的布局,非常方便。

效果图:
在这里插入图片描述

在这里插入图片描述

核心部分是手指触摸事件处理,自定义View通过重写OnTouchEvent事件进行处理:

 @Override
    public boolean onTouchEvent(MotionEvent ev) {


        if (!mScrollEnable) return super.onTouchEvent(ev);
        switch (ev.getAction()) {


            case MotionEvent.ACTION_DOWN:
                clickDownX = ev.getX();
                clickDownY = ev.getY();
                clickDownTime = System.currentTimeMillis();
                mX = ev.getX();
                mY = ev.getY();
                super.onTouchEvent(ev);
                return true;
            case MotionEvent.ACTION_MOVE:
                int scaledTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
                float x = ev.getX();
                float y = ev.getY();
                x = x - mX;
                y = y - mY;
                if (Math.abs(scaledTouchSlop) < Math.abs(x) || Math.abs(scaledTouchSlop) < Math.abs(y)) {
                    isScroll = true;
                }
                if (isScroll) {
                    mScrollLeft = (int) (getX() + x);
                    mScrollTop = (int) (getY() + y);
                    mScrollRight = (int) (getX() + getWidth() + x);
                    mScrollBottom = (int) (getY() + getHeight() + y);
                    //防止滑出父界面
                    if (mScrollLeft < 0 || mScrollRight > mParentWidth) {
                        mScrollLeft = (int) getX();
                        mScrollRight = (int) getX() + getWidth();
                    }
                    if (mScrollTop < 0 || mScrollBottom > mParentHeight) {
                        mScrollTop = (int) getY();
                        mScrollBottom = (int) getY() + getHeight();
                    }
                    layout(mScrollLeft, mScrollTop, mScrollRight, mScrollBottom);
                    hasScroll = true;
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                clickUpX = ev.getX();
                clickUpY = ev.getY();
                clickUpTime = System.currentTimeMillis();
                float stanceX = clickUpX - clickDownX;
                float stanceY = clickUpY - clickDownY;
                if(stanceX < 0){
                    stanceX = stanceX * -1;
                }
                if(stanceY < 0){
                    stanceY = stanceY * -1;
                }
                if((clickUpTime - clickDownTime) < 150 && stanceX < 50 && stanceY < 50){
                    if(onClickListener!=null){
                        onClickListener.onClick();
                    }
                }
                if (isScroll) {
                    isScroll = false;
                    setPressed(false);//重置点击状态
                    if (isAdsorb) {

                        //判断是否开启吸附
                        //获取屏幕中间值
                        int mind = getScreenWidth() / 2;
                        //获取控件宽度的中间值
                        int viewWithMind = getWidth() / 2;
                        //手指抬起时 自动吸附到屏幕两边
                        if (mScrollLeft + viewWithMind > mind) {


                            mScrollRight = getScreenWidth();
                            mScrollLeft = getScreenWidth() - getWidth();
                        } else {


                            mScrollRight = getWidth();
                            mScrollLeft = 0;
                        }
                        layout(mScrollLeft, mScrollTop, mScrollRight, mScrollBottom);
                    }
                    return true;
                }
                break;
        }
        return super.onTouchEvent(ev);
    }
  • 核心介绍

这里大概说一下,主要是MOVE操作,记录下手指的坐标,通过layout()方法重新给View定义新的位置,这里是通过计算到View的左右上下边距实现,和矩阵的思路是一样的。当然也可以改成矩阵实现,也可以通过x,y具体坐标去实现。方法多种哈。

  • 吸附
    主要是手指抬起后(ACTION_UP、ACTION_CANCEL),先去判断控件处于什么位置,拿到屏幕的宽度,看是在屏幕的左半边还是右半边,然后进行动画移动。左边的坐标自然是0,右边是(屏幕宽度-控件的宽度),然后进行动画移动重新布局。

  • 踩过的坑
    一开始用的吸附是这样做的:

DragView.this.animate()
                    .setInterpolator(new BounceInterpolator())
                    .setDuration(0)
                    .x(0)
                    .y(realY)
                    .start();

相信做过的人都不陌生,但是这样做是存在问题的。在一些情况下,里面的布局刷新或者重新绘制,这个吸附就会出现位置错误的情况,后来才改成另一种实现方式。同样遇到这样的问题的可参考本文实现。

  • 注意事项
    这里要注意ACTION_UP、ACTION_CANCEL这两个操作事件,因为部分手机手指抬起后是走的ACTION_CANCEL,部分是ACTION_UP,所以最好都做一下逻辑处理。

  • 具体调用方法
    在这里插入图片描述
    大致就是LayoutInflater实例化出ContentView,然后DolinDragView.setContentView()方法将控件放入。
    我这里做的Demo里面是一个轮播图,所以还有别的逻辑,需要的朋友可以去我主页资源处下载完整Demo。

DEMO地址

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值