Android QQ小红点的实现(附完整注释)


请尊重原创,转载请注明出处: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) / 
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值