安卓手机QQ红点拖拽消除的实现

MrLee2015-2-19 3809

新版手机QQ5.+上新增了一种“一键退朝”的功能,即在页面上的红点可进行拖拽消除。按照设计思路在Android上模仿手Q实现下拖拽的过程。

bezier



整体的思路,封装好一个view。在界面上找到四个点,即框出手势拖动点与红点之间的范围,利用贝塞尔曲线修饰边框,计算红点和手势拖动点间的距离,判断红点的消除与回弹。借用下设计图:

20141125101909968



首先确定以红点为坐标原点,在坐标上所要计算的就是p1, p2, p3, p4四个点,其中..为贝塞尔曲线,在p1p2和p3p4之间需要绘制半径为R和r的圆。
接下来需要的就是在拖动过程中计算(0,0)和(x0, y0)两点间的距离,通过距离控制贝塞尔曲线的弧度和圆的大小,实现模拟现实生活中弹性效果。
在代码中通过Path来控制p1, p2, p3, p4四个点所围成的范围,并填充相应地色值:
1.确定四个点,这里简单地将两个圆起始半径设置相等
float x1 = startX - offsetX;  
float y1 = startY + offsetY;  
  
float x2 = x - offsetX;  
float y2 = y + offsetY;  
  
float x3 = x + offsetX;  
float y3 = y - offsetY;  
  
float x4 = startX + offsetX;  
float y4 = startY - offsetY;  
  
path.reset();  
path.moveTo(x1, y1);  
path.quadTo(anchorX, anchorY, x2, y2);  
path.lineTo(x3, y3);  
path.quadTo(anchorX, anchorY, x4, y4);  
path.lineTo(x1, y1);  

2.填充范围和绘制圆形:
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY);  
canvas.drawPath(path, paint);  
canvas.drawCircle(startX, startY, radius, paint);  
canvas.drawCircle(x, y, radius, paint);  

3.在调用super.onDraw(canvas);方法绘制在canvas层上面的消息点图标imageView通过在代码中的onTouchEvent方法进行控制触摸点的相应位置,实现拖动的效果。
@Override  
    public boolean onTouchEvent(MotionEvent event) {  
        if(event.getAction() == MotionEvent.ACTION_DOWN){  
            // 判断触摸点是否在tipImageView中  
            Rect rect = new Rect();  
            int[] location = new int[2];  
            tipImageView.getDrawingRect(rect);  
            tipImageView.getLocationOnScreen(location);  
            rect.left = location[0];  
            rect.top = location[1];  
            rect.right = rect.right + location[0];  
            rect.bottom = rect.bottom + location[1];  
            if (rect.contains((int)event.getRawX(), (int)event.getRawY())){  
                isTouch = true;  
            }  
        }else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){  
            isTouch = false;  
            tipImageView.setX(startX - tipImageView.getWidth()/2);  
            tipImageView.setY(startY - tipImageView.getHeight()/2);  
        }  
        invalidate();  
        if(isAnimStart){  
            return super.onTouchEvent(event);  
        }  
        anchorX =  (event.getX() + startX)/2;  
        anchorY =  (event.getY() + startY)/2;  
        x =  event.getX();  
        y =  event.getY();  
        return true;  
    }  
4.拖动过程中计算两个圆心之间的距离,通过圆心间的距离调整圆心为(0, 0)圆的半径大小
float distance = (float) Math.sqrt(Math.pow(y-startY, 2) + Math.pow(x-startX, 2));  
radius = -distance/15+DEFAULT_RADIUS;  

用新的半径去绘制(0, 0)的圆,这样随着距离的增加,圆相应变小就给人如同快要沾不住黏黏的感觉。5.距离超过设定的最大范围,则设置为红点挣脱状态,如果手指抬起,则开始播放相应爆炸动画。
exploredImageView.setVisibility(View.VISIBLE);  
exploredImageView.setImageResource(R.drawable.tip_anim);  
((AnimationDrawable) exploredImageView.getDrawable()).stop();  
((AnimationDrawable) exploredImageView.getDrawable()).start(); 
6.在Activity布局中引用相应封装好的view即可。
  
最开始设想的view在类似于红点范围的一个控件,但是这样实现就达不到拖动到父类控件的范围之外,比如拖动红点超过页签布局范围时,红点则无法绘制。因此在QQ的消息列表中是将其设置相应全屏的一个view。背景为截图的上个背景,这样在最上一层实则只有红点的控件。这样就能相应地拖动红点到屏幕的各个位置。所以才会在红点列表爆照动画结束之前页签是不可点击,并且拖动红点的时候列表数据没有刷新。

本文链接:https://www.it72.com/1037.htm

推荐阅读
最新回复 (1)
返回