我正在参加「启航方案」,这是我参加的第2篇文章。

自定义签名工具相信咱们都轻车熟路,经过监听屏幕onTouchEvent事情,分别在按下(ACTION_DOWN)抬起(ACTION_UP)移动(ACTION_MOVE) 动作中处理触碰点的搜集和制作,很容易就达到了手签笔的作用。其间无非又涉及到线条的撤回、撤销、清除、画笔的粗细,也便是对搜集的点调集和线调集的增删操作以及画笔色彩宽的的更改。这些功能都在 完成一个自定义有限制区域的图例(视点自辨认)涂鸦工具类(上) 中介绍过。

但就在前不久遇到一个需求是要求手签笔能够和咱们使用钢笔签名类似的作用,当然这个功能目前是有一些公司有老练的SDK的,但咱们的需求是要不借助SDK,自己完成笔锋作用。那么,如何使画笔带笔锋呢?废话不多说,先上作用图:

Android:自定义View实现签名带笔锋效果

要完成笔锋作用咱们需要考虑几个要素:笔速笔宽按压力度(针对手写笔)。因为在onTouchEvent回调的次数是不变的,一旦笔速变快两点之间间隔就被拉长。此时的笔宽不能保持在上一笔的宽度,需要咱们经过核算刺进新的点,一起核算出对应点的宽度。同理当咱们笔速慢的时候,需要经过核算删去信息附近的点。要想笔锋自然,当然贝塞尔曲线是必不可少的。

这里咱们暂时没有将笔的按压值作为笔宽的核算,仅仅经过笔速来核算笔宽。

/**
 * 核算新的宽度信息
 */
public double calcNewWidth(double curVel, double lastVel,double factor) {
    double calVel = curVel * 0.6 + lastVel * (1 - 0.6);
    double vfac = Math.log(factor * 2.0f) * (-calVel);
    double calWidth = mBaseWidth * Math.exp(vfac);
    return calWidth;
}
/**
 * 获取点信息
 */
public ControllerPoint getPoint(double t) {
    float x = (float) getX(t);
    float y = (float) getY(t);
    float w = (float) getW(t);
    ControllerPoint point = new ControllerPoint();
    point.set(x, y, w);
    return point;
}
/**
 * 三阶曲线的控制点
 */
private double getValue(double p0, double p1, double p2, double t) {
    double a = p2 - 2 * p1 + p0;
    double b = 2 * (p1 - p0);
    double c = p0;
    return a * t * t + b * t + c;
}

最终也是最关键的当地,不再使用drawLine方式画线,而是经过drawOval方式画椭圆。经过前后两点核算出椭圆的四个点,经过笔宽核算出制作椭圆的个数并参加椭圆集。最终在onDraw方法中制作。

/**
 * 两点之间将视图搜集的点转为椭圆矩阵 完成笔锋作用
 */
public static ArrayList<SvgPointBean> twoPointsTransRectF(double x0, double y0, double w0, double x1, double y1, double w1, float paintWidth, int color) {
    ArrayList<SvgPointBean> list = new ArrayList<>();
    //求两个数字的平方根 x的平方+y的平方在开方记得X的平方+y的平方=1,这便是一个园
    double curDis = Math.hypot(x0 - x1, y0 - y1);
    int steps;
    //制作的笔的宽度是多少,制作多少个椭圆
    if (paintWidth < 6) {
        steps = 1 + (int) (curDis / 2);
    } else if (paintWidth > 60) {
        steps = 1 + (int) (curDis / 4);
    } else {
        steps = 1 + (int) (curDis / 3);
    }
    double deltaX = (x1 - x0) / steps;
    double deltaY = (y1 - y0) / steps;
    double deltaW = (w1 - w0) / steps;
    double x = x0;
    double y = y0;
    double w = w0;
    for (int i = 0; i < steps; i++) {
        RectF oval = new RectF();
        float top = (float) (y - w / 2.0f);
        float left = (float) (x - w / 4.0f);
        float right = (float) (x + w / 4.0f);
        float bottom = (float) (y + w / 2.0f);
        oval.set(left, top, right, bottom);
        //搜集椭圆矩阵信息
        list.add(new SvgPointBean(oval, color));
        x += deltaX;
        y += deltaY;
        w += deltaW;
    }
    return list;
}

至此一个简略的带笔锋的手写签名就完成了。 最终附上参考链接Github.

我是一个喜爱Jay、Vae的安卓开发者,喜爱结交四面八方的兄弟姐妹,欢迎咱们到沸点来点歌!