美文网首页
书写白板

书写白板

作者: zhenj1ang | 来源:发表于2019-06-17 15:00 被阅读0次
    软件界面

    应用需求

    通过触摸轨迹在屏幕上书写内容,其他功能都是围绕书写内容进行的,例如:两点拖拽,两点缩放,擦除.

    画线部分代码

      /**
         * 在SurfaceView触摸时间OnTouchEvent()传入坐标点和Action
         * 记录下坐标点生成贝塞尔曲线
         * @param x 横坐标
         * @param y  纵坐标
         * @param action 按下&移动&抬起&多点
         */
     public void setCurrent(float x, float y, int action) {
          /*mPath是drawPath的容器,drawPath的作用是局部渲染的path是一小段的path,用作于书写和擦除线条的判断   */
            if (!isStart()) {
                super.setCurrent(x, y, action);
                mPath.moveTo(x, y);
                mPath.addPathPoints(new float[]{x, y});
                paths.add(new SerPath());
            } else {
                mPath.addPathPoints(new float[]{x, y});
                drawPath = new SerPath();
                paths.add(drawPath);
                super.setCurrent(x, y, action);
                double distance = Math.sqrt(Math.pow(Math.abs(x - getLast().x), 2) + Math.pow(Math.abs(y - getLast().y), 2));
    
                if (distance > 400) {  //如果距离突变过长,判断为无效点,直接current回退到上一次纪录的last的点,并且用UP时间结束这次path draw
    //                super.setCurrent(getLast().x, getLast().y, MotionEvent.ACTION_UP);
                    return;
                }
    
                cx = getLast().x;
                cy = getLast().y;
    
    
                midX = (x + cx) / 2;
                midY = (y + cy) / 2;
    
                startX = getMid().x;
                startY = getMid().y;
    
                getMid().x = midX;
                getMid().y = midY;
    
    
                drawPath.moveTo(startX, startY);
                double s = Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2));
                if (action == MotionEvent.ACTION_UP) {
                    if (s > 5) {
                        drawPath.lineTo(x, y);
                        mPath.lineTo(x, y);
                    }
                } else {
                    if (s < 200) {
                        if (s < 30) {//1.10 //2.12 //3.15 //在一些性能较差的触摸屏会出现线条飞线的问题
                            drawPath.cubicTo(cx, cy, midX, midY, x, y);
                            mPath.cubicTo(cx, cy, midX, midY, x, y);
                        } else {
                            drawPath.quadTo(cx, cy, midX, midY);
                            mPath.quadTo(cx, cy, midX, midY);
                        }
                    } else {
                        drawPath.quadTo(cx, cy, midX, midY);
                        mPath.quadTo(cx, cy, midX, midY);
                    }
                }
            }
            prevX = x;
            prevY = y;
        }
    

    橡皮擦部分代码

     /**
         * 橡皮擦擦除线条核心
         * @param eraserPath 橡皮擦轨迹
         * @param pens 所有跟橡皮擦有交集的线条
         */
     public boolean eraser(Path eraserPath, ArrayList<NewCurv> pens) {
            Region eraserRegion = new Region();
            RectF eraserRectF = new RectF();
            eraserPath.computeBounds(eraserRectF, false);
            eraserRegion.setPath(eraserPath, new Region((int) eraserRectF.left, (int) eraserRectF.top, (int)   
            eraserRectF.right, (int) eraserRectF.bottom));
            Rect bounds = eraserRegion.getBounds();
            RectF rectF = new RectF(bounds.left, bounds.top, bounds.right, bounds.bottom);
         
            boolean split = false;
            int size = this.mPath.pathPoints.size();
            NewCurv pen = new NewCurv(2, cPaint);
            PathMeasure pm = new PathMeasure();
    
            if (size != 0) {
                //size = 0
                System.out.println("size != 0");
                pen.cachePoints.add(mPath.pathPoints.get(0));
    
                float[] smallSegPoint = new float[2];
                if (mPath.pathPoints != null && !mPath.pathPoints.isEmpty()) {
                    for (int j = 1; j < mPath.pathPoints.size(); j++) {
                        SerPath path = new SerPath();
                        float pointPrev[] = mPath.pathPoints.get(j - 1);
                        float pointNow[] = mPath.pathPoints.get(j);
                        path.moveTo(pointPrev[0], pointPrev[1]);
                        path.lineTo(pointNow[0], pointNow[1]);
                        paths.add(path);
                    }
                } else {
                    return false;
                }
                for (int i = 1; i <= size - 1; i++) {
                    if (i > paths.size() - 1) {
                        return false;
                    }
                    System.out.println("for");
                    float[] points = this.mPath.pathPoints.get(i); //todo 小板擦会挂掉,因为paths数组是空的
                    SerPath path = paths.get(i); /////////////////////////////
                    Region pathRegion = new Region();
                    RectF segRect = new RectF();
                    path.computeBounds(segRect, false);
                    //判断是否在触摸点范围的小矩形里面
                    /*当板擦直接覆盖住目标点**/
    //                RectF segRect = new RectF(pathRect.left,  pathRect.top,  pathRect.right,  pathRect.bottom);
    
                    pathRegion.setPath(path, new Region((int) segRect.left, (int) segRect.top, (int) segRect.right, (int) segRect.bottom));
    
                    Rect rect = new Rect((int) segRect.left, (int) segRect.top, (int) segRect.right, (int) segRect.bottom);
                    if (PanelUtil.isRectIntersectRegion(segRect, eraserRegion) || bounds.intersect(rect) || eraserRegion.quickContains(rect)) {
                        pm.setPath(path, false);
                        split = true;
                        boolean cut = false;
                        for (int j = 0; j < pm.getLength(); j++) {  //遍历细段
                            pm.getPosTan(j, smallSegPoint, null);
                            //细分到某段 找到擦除的点
                            if (eraserRegion.contains((int) smallSegPoint[0], (int) smallSegPoint[1]) || bounds.contains((int) smallSegPoint[0], (int) smallSegPoint[1])) { //此时得到的是线条1的终结点
                                if (!cut) {
                                    cut = true;
                                    if (pen.getPointCount() == 1 && j == 0 && i == 1) { //如果是擦除开头的话,重新开一跳新线条
                                        pen = new NewCurv(2, cPaint);
                                    } else {
                                        pen.cachePoints.add(smallSegPoint); //线条1的终结点添加到目标线条cachePoints
                                        /*终结并渲染该线条, 然后新开一条线条**/
                                        pen.buildPathAll();
                                        if (pen.getLength() >= 2)
                                            pens.add(pen);
                                        pen = new NewCurv(2, cPaint);
                                    }
                                }
                            } else if (j >= pm.getLength() - 1) {
                                pen.cachePoints.add(points);
                            } else if ((cut || pen.getPointCount() == 0)) {//新开的第二条线,后面橡皮不相交的部分都塞进去
                                cut = false;
                                float[] copySeg = new float[2];
                                copySeg[0] = smallSegPoint[0];
                                copySeg[1] = smallSegPoint[1];
                                pen.cachePoints.add(copySeg);  //起点是这个
                            }
    
                        }//for
                    } else if (pen.getPointCount() == 0) {
                        pen.cachePoints.add(points);
                    } else {
                        pen.cachePoints.add(points);
                    }
                }
    
                if (pen.getPointCount() > 1) {
                    pen.buildPathAll();
                    if (pen.getLength() >= 2)
                        pens.add(pen);
    
                }
            }
    
            return split;
        }
    

    总得来说就是利用橡皮檫的Rect跟线条的drawpath进行判断,生成开始点过程点结束点,重新生成一条新的线条


    上传服务器微信扫码效果

    简单写一下流程,细分的太多内容

    相关文章

      网友评论

          本文标题:书写白板

          本文链接:https://www.haomeiwen.com/subject/ixuafctx.html