SurfaceView - масштабирование без потери качества - PullRequest
0 голосов
/ 02 июля 2019

Помогите решить мою проблему, пожалуйста. Поиск в Google не дает результатов.
У меня есть собственный SurfaceView, на холсте которого через отдельный поток я рисую различные формы и текст. Этот SurfaceView обернут в пользовательский FrameLayout, который реализует масштабирование пинч для ребенка. Так что при зуме качество рисунков теряется, хотя, если вы используете обычный вид с холстом, все в порядке. TextureView имеет ту же проблему. Я бы хотел использовать обычный вид, но мне нужно постоянно перерисовывать холст.
У кого-нибудь есть мысли?

Например, я рисую сетку с числами:

PixelGridSurfaceView

public class PixelGridSurfaceView extends SurfaceView
        implements SurfaceHolder.Callback {

private DrawThread drawThreadSV;
private float pixelRadius = 0;
private int numColumns = 90, numRows = 90;

public PixelGridSurfaceView(Context context) {
    super(context);
    getHolder().addCallback(this);
}

public PixelGridSurfaceView (Context context, AttributeSet attributeSet) {
    super(context, attributeSet);
    getHolder().addCallback(this);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // Add padding to maximum width calculation.
    final int desiredWidth = Math.round(getPaddingLeft() + getPaddingRight());


    final int desiredHeight = Math.round(getPaddingTop() +
            getPaddingBottom());

    // Reconcile size that this view wants to be with the size the parent will let it be.
    final int measuredWidth = reconcileSize(desiredWidth, widthMeasureSpec);
    final int measuredHeight = reconcileSize(desiredHeight, heightMeasureSpec);

    // calculate best pixel size
    float cellWidth = (float) measuredWidth / numColumns;
    float cellHeight = (float) measuredHeight / numRows;

    pixelRadius = cellHeight < cellWidth ? cellHeight : cellWidth;
    pixelRadius = (float) Math.floor(pixelRadius);

    // Store the final measured dimensions.
    setMeasuredDimension((int) pixelRadius * numColumns, measuredHeight);
}

private int reconcileSize(int contentSize, int measureSpec) {
    final int mode = MeasureSpec.getMode(measureSpec);
    final int specSize = MeasureSpec.getSize(measureSpec);
    switch (mode) {
        case MeasureSpec.EXACTLY:
            return specSize;
        case MeasureSpec.AT_MOST:
            if (contentSize < specSize) {
                return contentSize;
            } else {
                return specSize;
            }
        case MeasureSpec.UNSPECIFIED:
        default:
            return contentSize;
    }
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    drawThreadSV = new DrawThread(new SurfaceViewHolder(getHolder()));
    drawThreadSV.setPixelRadius(getContext(), pixelRadius);
    drawThreadSV.setNumRowsColumns(numColumns, numRows);
    drawThreadSV.setRunning(true);
    drawThreadSV.start();
}



@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    boolean retry = true;
    drawThreadSV.setRunning(false);

    while(retry) {
        try {
            drawThreadSV.join();
            retry = false;
        }
        catch (InterruptedException e) {
        }
    }
}
}

DrawThread

public class DrawThread extends Thread {

    private boolean running = false;
    private ISurfaceHolder surfaceHolder;
    private int numColumns, numRows;
    private Paint linePaint, cellsPaint;
    private TextPaint fontPaint;
    private float pixelRadius = 0;
    private float baselineX, baselineY;
    private String number = "4";

    DrawThread(ISurfaceHolder surfaceHolder) {
        this.surfaceHolder = surfaceHolder;
        linePaint = new Paint();
        cellsPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        fontPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setColor(Color.BLACK);
        cellsPaint.setColor(Color.WHITE);
        linePaint.setStyle(Paint.Style.STROKE);
    }

    void setPixelRadius(Context context, float pixelRadius) {
        this.pixelRadius = pixelRadius;
        fontPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, pixelRadius / 2.5f, context.getResources().getDisplayMetrics()));
    }

    void setNumRowsColumns(int numColumns, int numRows) {
        this.numColumns = numColumns;
        this.numRows = numRows;
    }

    void setRunning(boolean running) {
        this.running = running;
    }


    @Override
    public void run() {
        Canvas canvas;
        while (running) {
            canvas = null;
            try {
                canvas = surfaceHolder.lockCanvas();
                if (canvas == null)
                    continue;
                drawPath(canvas);

            } finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }

    private void drawPath(Canvas canvas) {
        canvas.drawColor(Color.WHITE);
        for (int i = 0; i < numColumns; i++) {
            for (int j = 0; j < numRows; j++) {
                drawPixel(canvas, cellsPaint, i, j);
            }

        }
        for (int i = 0; i < numColumns; i++) {
            for (int j = 0; j < numRows; j++) {
                numberSizeAndPosition(i, j);
                drawPixel(canvas, linePaint, i, j);
                canvas.drawText(number, baselineX, baselineY, fontPaint);
            }

        }
    }

    private void drawPixel(Canvas canvas, Paint paint, int i, int j) {
        canvas.drawRect(i * pixelRadius, j * pixelRadius,
                (i + 1) * pixelRadius, (j + 1) * pixelRadius,
                paint);
    }

    private void numberSizeAndPosition(int i, int j) {

        float centerX = (i * pixelRadius) + pixelRadius / 2.0f;
        float centerY = (j * pixelRadius) + pixelRadius / 2.0f;

        Rect bounds = new Rect();
        fontPaint.getTextBounds(number, 0, number.length(), bounds);
        float textWidth = bounds.width();
        float textHeight = bounds.height();

        baselineY = centerY + textHeight * 0.5f;
        baselineX = centerX - textWidth * 0.5f;
    }
}

coloring.xml

...
<ZoomLayout
        android:id="@+id/zoomLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        android:scrollbars="vertical|horizontal"
        android:background="@color/colorWhite"
        app:hasClickableChildren="true"
        app:horizontalPanEnabled="true"
        app:maxZoom="9.0"
        app:maxZoomType="zoom"
        app:minZoom="1.0"
        app:minZoomType="zoom"
        app:overPinchable="false"
        app:overScrollHorizontal="false"
        app:overScrollVertical="false"
        app:verticalPanEnabled="true"
        app:zoomEnabled="true">

        <PixelGridSurfaceView
            android:id="@+id/gridSurfaceView"
            android:layout_width="1000dp"
            android:layout_height="1000dp"
            android:layout_centerInParent="true"/>
    </ZoomLayout>
...

С увеличением, низкое качество

...