在Android上裁剪和保存可扩展/可缩放的Canvas View的一部分

时间:2018-06-01 22:35:25

标签: java android canvas

我开发了一个绘制Android应用程序的流程图,但我正在努力保存绘图。我实现了一种保存图像的方法,但这种方法的作用基本上是打印出当前在绘图表面上可见的内容。由于表面是可缩放的,因此当时在屏幕上可见的并不总是图画的良好镜头。在保存绘图之前,应用程序需要确保所有图表都可见。

以下是一些屏幕截图,可以进一步解释问题所在。

让我们说用户绘制了一个如下图:

enter image description here

然后开始检查图表。您可以放大并从上到下查看所有图表。完全向下滚动并确保一切正常后,此时点击保存按钮:

enter image description here

这是保存在您图库中的.PNG文件:

enter image description here

为了更好地拍摄图表,您必须向后缩小并确保图表位于画布中间并且其所有部分都可见。如果此时单击“保存”按钮:

enter image description here

这是输出,非常不错:

enter image description here

如何在不需要用户完成工作的情况下全面拍摄图表?这是我为保存图片而编写的代码:

private void saveImage(){
    View content = drawingSurface;
    drawingSurface.prepareToSaveAsImage(true);
    content.setDrawingCacheEnabled(true);
    content.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
    Bitmap bitmap = content.getDrawingCache();
    FileOutputStream ostream;
    File folder = new File(pathToFolder);
    if (!folder.exists()){
        folder.mkdirs();
    }
    File file = new File (pathToImage);
    try {
        file.createNewFile();
        ostream = new FileOutputStream(file);
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, ostream);
        ostream.flush();
        ostream.close();
        Toast.makeText(getApplicationContext(), "image saved" + pathToImage, Toast.LENGTH_SHORT).show();
    } catch (Exception e) {
        e.printStackTrace();
        Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show();
    }
    drawingSurface.prepareToSaveAsImage(false);
}

有没有办法获取整个Canvas并让用户选择它的一部分?

DrawingSurface是一个可缩放和可滚动的表面。

编辑:一些方法可让您了解缩放,缩放和滚动的工作原理。

DrawingSurface的onDraw()方法:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    this.canvas = canvas;
    canvas.save();
    posX = Math.min(MAX_COORDINATE, Math.max(MIN_COORDINATE, posX));
    posY = Math.min(MAX_COORDINATE, Math.max(MIN_COORDINATE, posY));
    canvas.translate(posX, posY);
    canvas.scale(scaleFactor, scaleFactor);
    if (!hideLines){
        paint.setColor(Color.GRAY);
        for (int a = -10; a < 10; a++) {
            for (int b = -10; b < 10; b++) {
                canvas.drawLine(1000 * a, -10000, 1000 * a, 10000, paint);
                canvas.drawLine(-10000, 1000 * b, 10000, 1000 * b, paint);
            }
        }
        paint.setColor(Color.BLACK);
    }
    for (Shape shape : shapes){
        shape.drawThis();
    }
    canvas.restore();
}

ScaleListener类在用户收入或放出时放大/缩小:

private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    @Override
    public boolean onScale(ScaleGestureDetector detector) {
        if (selectedShape != null){
            float shapeScaleFactor = detector.getScaleFactor();
            selectedShape.scale(shapeScaleFactor);
        } else {
            scaleFactor *= detector.getScaleFactor();
            scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 1.0f));
        }
        invalidate();
        return true;
    }
}

检测滚动的onTouch()方法:

public boolean onTouchEvent (MotionEvent event){
    scaleGestureDetector.setQuickScaleEnabled(true);
    scaleGestureDetector.onTouchEvent(event);
    final int action = event.getAction();

    float[] coords = new float[2];
    coords[0] = event.getX();
    coords[1] = event.getY();

    Matrix matrix = new Matrix();
    matrix.set(getMatrix());

    matrix.preTranslate(posX, posY);
    matrix.preScale(scaleFactor, scaleFactor);
    matrix.invert(matrix);
    matrix.mapPoints(coords);

    final int x = Math.round(event.getX());
    final int y = Math.round(event.getY());

    cX = Math.round(coords[0]);
    cY = Math.round(coords[1]);

    switch (action & MotionEvent.ACTION_MASK){
        case MotionEvent.ACTION_DOWN: {
            startClickTime = Calendar.getInstance().getTimeInMillis();
            isZooming = false;
            lastX = x;
            lastY = y;
            break;
        }
        case MotionEvent.ACTION_MOVE: {
            if (scaleGestureDetector.isInProgress()){
                isZooming = true;
            } else if (!isZooming){
                final int dX = (x - lastX);
                final int dY = (y - lastY);
                if (selectedShape != null){
                    selectedShape.translate(Math.round(dX / scaleFactor), Math.round(dY / scaleFactor));
                } else {
                    posX += dX;
                    posY += dY;
                }
            }
            lastX = x;
            lastY = y;
            invalidate();
            break;
        }
        case MotionEvent.ACTION_UP: {
            long clickDuration = Calendar.getInstance().getTimeInMillis() - startClickTime;
            if (clickDuration < MAX_CLICK_DURATION && !scaleGestureDetector.isInProgress()){
                // Kullanıcı sadece dokundu. Nereye dokunduğuna bakılmalı.
                boolean touchedAShape = false;
                boolean addedTextOrLine = false;
                Shape lastShape;
                // Bir şekle dokunduysa o şekil seçili olmalı.
                for (Shape shape : shapes){
                    if (shape.contains(new Point(cX, cY))){
                        if (selectedShape != null){
                            addedTextOrLine = true;
                            if (selectedShape == shape){
                                getShapeTextInput(shape);
                            } else {
                                selectedShape.setLine(shape);
                            }
                        }
                        select(shape);
                        touchedAShape = true;
                    }
                }
                // Boş alana dokunuldu, önceden seçilmiş olan şekil artık seçili olmamalı.
                if ((!touchedAShape) || addedTextOrLine){
                    if (selectedShape != null) selectedShape.setSelect(false);
                    selectedShape = null;
                }
            }
            invalidate();
        }
    }
    return true;
}

0 个答案:

没有答案