Android: Customize View to achieve signature with stroke effect

dec5984affdfef4012848c9e8f4741c2.png

I believe that everyone is familiar with the custom signature tool. By monitoring the onTouchEvent event on the screen, the collection and drawing of touch points are processed in the actions of pressing (ACTION_DOWN) , lifting (ACTION_UP) , and moving (ACTION_MOVE) , respectively , so that the effect of a stylus can be easily achieved. It involves nothing more than the withdrawal, cancellation, clearing of lines, the thickness of the brush, that is, the addition and deletion of the collected point set and line set, and the change of the color width of the brush. These functions are all introduced in https://juejin.cn/post/7202260878930591802 to implement a custom limited area legend (angle self-identification) graffiti tool class (above) .

Author: Deja vu 2022 Link: https://juejin.cn/post/7244192848063627325

But not long ago, I encountered a requirement that the signature pen can have a similar effect to our pen signature. Of course, some companies have mature SDKs for this function, but our requirement is to realize the pen effect by ourselves without the help of the SDK. So, how to make the brush with the tip? Without further ado, let’s start with the renderings:

a2398cabb666716d5c25c499f0f658f1.jpeg

To achieve the stroke effect, we need to consider several factors: pen speed , pen width , pressing pressure (for the stylus) . Because the number of callbacks in onTouchEvent is constant, once the pen speed becomes faster, the distance between the two points will be lengthened. At this time, the pen width cannot be maintained at the width of the previous stroke. We need to insert new points through calculation and calculate the width of the corresponding point at the same time. Similarly, when our writing speed is slow, we need to delete points with similar information through calculation. To have a natural stroke, of course Bezier curves are essential.

Here we don't use the pressing value of the pen as the calculation of the pen width for the time being, but only calculate the pen width by the pen speed.

/**
 * 计算新的宽度信息
 */
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;
}

Finally, and the most critical point, instead of using drawLine to draw lines, draw ellipses through drawOval . Calculate the four points of the ellipse through the two points before and after, and calculate the number of drawn ellipses through the pen width and add them to the ellipse set. Finally draw in the onDraw method.

/**
 * 两点之间将视图收集的点转为椭圆矩阵 实现笔锋效果
 */
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;
}

So far, a simple handwritten signature with a stroke has been realized. Finally, attach the reference link Github (https://github.com/GdinKing/HandWrite)

Follow me for more knowledge or contribution

477c60ffcb46fc7b783969822db60479.jpeg

575af5819ceaf5b0cd2f3e0a0ed9939e.jpeg

Guess you like

Origin blog.csdn.net/c6E5UlI1N/article/details/131238031