美文网首页
仿QQ消息拖拽,让你的View动起来

仿QQ消息拖拽,让你的View动起来

作者: Seven鑫洋 | 来源:发表于2017-09-08 16:50 被阅读78次

    前言

    ​ 玩过QQ的人应该都不会对QQ消息的小红点陌生吧。在我们的实际应用开发中有时候也是会遇到这种消息拖拽消失的需求。这时我们要么自己造轮子,要么去Google找轮子。而我们在网上找的轮子呢,大部分都是自定义View然后这个View支持拖动,是一个死的轮子。

    ​ 而今天,我们就是要改变现状,让我们的轮子转起来,写一个工具类,只要用这个工具类那么你的所有的View就都可以动起来,进行拖拽。而不是写死在View内部。有没有觉得很帅?!快鼓掌


    效果图

    挽起袖子,撸起来!


    第一步 让点动起来

    ​ 在这里我们实现的功能非常简单,就是我们自定义view,在这个View中当我们按下手指的时候,会画两个红点,这两个红点最开始是重合的,当我们移动手指的时候,一个红点随着我们的手指移动,而另一个红点,则随着我们手指移动的距离越远半径而变得越来越小,知道这个半径等于0,不再画这个红点为止。

    ​ 这一步应该是比较容易的,就不写代码了,了解了思路是最重要的,如果你看到这里就懵逼了,那么我不建议你往下看了,这可能对你来说比较难了,我建议你去看一点自定义View的基础之后再来看本文章。

    第二步 添加贝塞尔曲线

    ​ 我们看QQ消息的拖拽,控件与红色圆点之间并不是空白的,而是有填充的,而且不是直线填充,是有两条曲线的,给人非常舒服的感觉,没错,这两条曲线就是贝塞尔曲线

    ​ 对于普通的二阶贝塞尔曲线还是比较容易理解的,当然对于高阶我自己有时候也是懵逼的 =.=

    ​ 这里有一个比较好的贝塞尔曲线的游戏,可以去玩一玩

    ​ 如果要加入这两个曲线那么就需要找到二阶贝塞尔曲线的控制点和起始点,起始点就是两个圆的切线位置,控制点我们去黄金分割点。

    贝塞尔分析

    这个分析过程我们主要是求四个蓝色的起始点,会用到部分三角函数的知识,但是这应该都是初中的内容,我相信对各位都不是问题。
    而控制点就更简单了,说就是dx和dy的黄金分割点0.618

    Path bezier = new Path();

        float dx = mDragPoint.x - mFixedPoint.x;
        float dy = mDragPoint.y - mFixedPoint.y;
        float tanA = dy/dx;
        double A = Math.atan(tanA);
    
        float p1x = (float) (mFixedPoint.x + Math.sin(A)*mFixedRadius);
        float p1y = (float) (mFixedPoint.y - Math.cos(A)*mFixedRadius);
    
        float p2x = (float) (mDragPoint.x + Math.sin(A)*mDragRadius);
        float p2y = (float) (mDragPoint.y - Math.cos(A)*mDragRadius);
    
        float p3x = (float) (mDragPoint.x - Math.sin(A)*mDragRadius);
        float p3y = (float) (mDragPoint.y + Math.cos(A)*mDragRadius);
    
        float p4x = (float) (mFixedPoint.x - Math.sin(A)*mFixedRadius);
        float p4y = (float) (mFixedPoint.y + Math.cos(A)*mFixedRadius);
    
        float controlX = mFixedPoint.x + (mDragPoint.x-mFixedPoint.x)*GOLD_POINT;
        float controlY = mFixedPoint.y + (mDragPoint.y-mFixedPoint.y)*GOLD_POINT;
    
        bezier.moveTo(p1x,p1y);
        bezier.quadTo(controlX,controlY,p2x,p2y);
        bezier.lineTo(p3x,p3y);
        bezier.quadTo(controlX,controlY,p4x,p4y);
        bezier.close();
    

    这是贝塞尔曲线的主要代码,应该也不难。

    这个时候我们再把我们的程序运行起来,是不是有点样子了?这时候我们的工作已经做了一大半了 。

    第三步 绑定View,实现轮子

    ​ 到目前位置,我们的程序还是和网上的轮子都差不多,写在自定义View里面。

    ​ 我们在BubbleView中添加一个静态的attach方法,将需要拖动的View传进去,然后把刚才重写的OnTouch给删了,是的你没看错,就是删了

    ​ 我们要做的第一件事就是在我们点击这个View的时候让这个View消失,是的你没看错,就是让它消失。此功能简单否?简单也!设置setVisibility(View.INVISIBLE)

    ​ 我们再分析一下其他功能,我们是要我们的View随便拖动,而不仅仅是在我们setContent的这个ViewGroup中,那么我就不能单纯的在我们设置的父布局中进行移动了,如果只是在设置的根布局中,局限性就很大了。
    有没有好办法?,答案是肯定的,当然有,没有这个轮子不就毁了?
    那是什么呢,就是我们大名鼎鼎的WindowManager,不用怕就是它,加在WindowManager上就可以让我们的视图随便拖动了,只要是你拖到的地方都行。

    ​ 所有的窗口行的应用都是用到了WindowManager,有兴趣的可以去研究一下

    ​ 我们在刚才点击这个View手指按下的时候已经让这个View不可见了,那么我们不要去操作他,而是去操作它的镜像,没错镜像。

    public static Bitmap getBitmapByView(View view){
        view.buildDrawingCache();
        Bitmap bitmap = view.getDrawingCache();
        return  bitmap;
    }
    

    代码非常简单,那么手机的截屏你是不是也知道怎么弄了?写一个轮子试试吧!

    同时,我们添加一个刚才我们写BubbleView。并将我们获得的这个镜像传递进去,是不是有思路了。对,就是让我们传入的这个bitmap随着刚才手指移动而移动,从而实现了我们View镜像的移动,对于用户来说我们的View就变得可拖动起来了。

    这里我们定义两个监听接口,一个是用来监听拖动距离超出最大距离视图爆炸和小于最大最距离的时候,视图回弹。另一个是对视图消失的回调。

    这里主要的思路,如果你的思路清楚了,那么一切都不是问题。

    思想>CODING

    当然这里面还是有许多的细节问题。但是大的思路明确了,小细节就是慢慢调了。比如,状态栏透明等小问题,还有状态栏的高度的加减问题,回弹动画,爆炸动画等。不过我相信这些都是小事了。

    轮子

    ​ 当然,肯定有人会直接想要轮子的,来给你个轮子

    相关文章

      网友评论

          本文标题:仿QQ消息拖拽,让你的View动起来

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