请尊重原创,转载请注明出处:http://blog.csdn.net/mabeijianxi/article/details/50560361
最近抽了些时间找了些资料,做了一个相对成熟的类似QQ小红点的拖拽控件。
先看下最后的效果:
simple与lib下载地址:https://github.com/mabeijianxi/stickyDots
一、分析:
1、首先分析这个控件的组成部分:
通过观察可以很明显的得出这个控件由三部分组成,一个固定不动的圆,一个连接部分,一个可能是圆的拖拽部分,由于不确定暂时把它看作圆
2、分析三个部分需要如何绘制。
(1)两个圆:这个比较简单,直接在复写view的onDraw方法,在里面执行canvas.drawCircle(),当然还需要传入圆心坐标和半径大小。
(2)连接部分:这个用过ps的矢量工具的应该知道。这里的是两条二阶贝塞尔曲线加两条直线。如图,二阶贝塞尔曲线是由起始点(P0,P2)和一个控制点(P1)组成。
二阶贝塞尔曲线在android中的绘制方法可以调用Path类:
Path mPath=new Path();
mPath.moveTo(P0.x,P0.y);
mPath.quadTo(P1..x, P1.y, P2.x, P2.y);
直线就比较简单了:
mPath.lineTo(L0.x,L0.y);
(3)如何把每个部分结合起来,并且绘制在屏幕上:
有一个圆的圆心是固定的,可以先绘制。完成以后需要绘制连接部分,这个连接部分有两条曲线,两条直线,所以需要5个点才能绘制出来,
其中1个贝塞尔曲线的控制点,因为对称,所以控制点两条曲线公用一个控制点,。至于剩下的四个点,这里选取两个圆的外切点,如图:
接下来就是计算了,首先拖拽圆的圆心、半径可以知道,圆心坐标就是你手指触摸的位置,可以重写onTouchEvent()得到,固定圆圆心是不会变的,至于半径暂时给个确定值。
第一步:计算外切点:
根据两圆心所连接成的执行计算斜率:
公式是k=dy/dy;
dy=O1.y-O2.y;
dx=O1.x-O2.x;
有了斜率、半径与圆心计算切点就没有问题了,都是三角函数的一些换算,就不多说,具体的可以下载或者查看这个工具类GeometryUtil的计算过程。
第二步:计算控制点,其实就是O1与O2的中心点,x=(O1.x+O2.x)/2 y=(O1.y+O2.y)/2
第三步:根据计算出来的五个点开始绘制闭合图形
这里我选择B点开始绘制:
移动到B点:mPath.moveTo(B.x,B.y)
从B点向A点作二阶贝塞尔曲线:mPath.quadTo(M.x,M.y,A.x,A.y)
从A向C绘制直线:mPath.lineTo(C.x,C.y)
从C向D绘制二阶贝塞尔曲线:mPath.quadTo(M.x,M.y,D.x,D.y)
直接封闭图形就行了:mPath.close()
二、静态图像绘制:
下面的静态绘制的代码:
package com.mabeijianxi.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.View;
/**
* Created by mabeijianxi on 2016/1/25.
*/
public class StickyView extends View {
/**
* 拖拽圆的圆心
*/
PointF mDragCanterPoint = new PointF(250, 450);
/**
* 固定圆的圆心
*/
PointF mFixCanterPoint = new PointF(250, 250);
/**
* 控制点
*/
PointF mCanterPoint = new PointF(250, 400);
/**
* 固定圆的切点
*/
PointF[] mFixTangentPointes = new PointF[] { new PointF(235, 250),
new PointF(265, 250) };
/**
* 拖拽圆的切点
*/
PointF[] mDragTangentPoint = new PointF[] { new PointF(230, 450),
new PointF(270, 450) };
/**
* 拖拽圆半径
*/
float mDragRadius = 20;
/**
* 固定圆半径
*/
float mFixRadius = 15;
private int statusBarHeight;
private Paint mPaint;
private Path mPath;
public StickyView(Context context) {
super(context);
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setAntiAlias(true);
mPath = new Path();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(0, -statusBarHeight);
canvas.drawCircle(mFixCanterPoint.x, mFixCanterPoint.y, mFixRadius,
mPaint);
float dy = mDragCanterPoint.y - mFixCanterPoint.y;
float dx = mDragCanterPoint.x - mFixCanterPoint.x;
mCanterPoint.set((mDragCanterPoint.x + mFixCanterPoint.x) / 2,
(mDragCanterPoint.y + mFixCanterPoint.y) /