# 拖拽效果

拖拽效果的实现其实是用贝塞尔曲线去构成的,这里上一张图就很明白

img

可以看到,所谓的拖拽效果只是在两个圆圈之间根据两个圆同侧切点和圆心连线中点三个点构建一条二阶贝塞尔曲线,另一侧也是,将其用颜色填充,就构成了qq红点的拖拽效果,是不是很简单

那么我们这里的目标就是先算出p0,p1,Q0三个点的坐标

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
float endX = nowFingerPoint.x;
float endY = nowFingerPoint.y;
float dx = endX - startX;
float dy = endY - startY;

float distance = (float) Math.sqrt(Math.pow(endY-startY, 2) + Math.pow(endX-startX, 2));
radius = 50 - distance/15;
radius = radius<20 ? 20 : radius;

double a = Math.atan(dy / dx);
float offsetX = (float) (radius * Math.sin(a));
float offsetY = (float) (radius * Math.cos(a));

// 根据角度算出四边形的四个点
float x1 = startX - offsetX;
float y1 = startY + offsetY;

float x2 = endX - offsetX;
float y2 = endY + offsetY;

float x3 = endX + offsetX;
float y3 = endY - offsetY;

float x4 = startX + offsetX;
float y4 = startY - offsetY;
  • 然后要做的就是画两个圆点,以及把这四个点连起来构成贝塞尔曲线
1
2
3
4
5
6
7
8
9
10
11
float anchorX = (startX + endX) / 2;
float anchorY = (startY + endY) / 2;

path.reset();

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);
  • 画圆点,响应移动事件这些就不写了,我直接贴源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
public class QQ_message_drag_effect extends View {
public QQ_message_drag_effect(Context context) {
super(context);
}

public QQ_message_drag_effect(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}

public QQ_message_drag_effect(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

int width;
int height;


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(width = ((ViewGroup)getParent()).getMeasuredWidth(),height = ((ViewGroup)getParent()).getMeasuredHeight());
}

float radius = 50;
PointF startPoint = new PointF(300,500);
PointF nowFingerPoint = new PointF();
boolean isMoveing = false;

Paint paint = new Paint();
Path path = new Path();

@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
if((x < startPoint.x + radius && x > startPoint.x - radius) &&
(y < startPoint.y + radius && y > startPoint.y - radius)){
isMoveing = true;
}
break;
case MotionEvent.ACTION_MOVE:
if(isMoveing){
nowFingerPoint.y = y;
nowFingerPoint.x = x;
invalidate();
}
break;
case MotionEvent.ACTION_UP:
isMoveing = false;
radius = 50;
invalidate();
break;
}


return true;
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

float startX = startPoint.x;
float startY = startPoint.y;

paint.setColor(Color.RED);
canvas.drawCircle(startX,startY,radius,paint);


if(isMoveing){

float endX = nowFingerPoint.x;
float endY = nowFingerPoint.y;
float dx = endX - startX;
float dy = endY - startY;

float distance = (float) Math.sqrt(Math.pow(endY-startY, 2) + Math.pow(endX-startX, 2));
radius = 50 - distance/15;
radius = radius<20 ? 20 : radius;

double a = Math.atan(dy / dx);
float offsetX = (float) (radius * Math.sin(a));
float offsetY = (float) (radius * Math.cos(a));

// 根据角度算出四边形的四个点
float x1 = startX - offsetX;
float y1 = startY + offsetY;

float x2 = endX - offsetX;
float y2 = endY + offsetY;

float x3 = endX + offsetX;
float y3 = endY - offsetY;

float x4 = startX + offsetX;
float y4 = startY - offsetY;

float anchorX = (startX + endX) / 2;
float anchorY = (startY + endY) / 2;

path.reset();

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);


canvas.drawPath(path,paint);

canvas.drawCircle(endX,endY,radius,paint);
}
}
}

参考:https://blog.csdn.net/asffghfgfghfg1556/article/details/80409902