You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何匹配Android Canvas与A3纸张尺寸并添加等距网格背景?

Android Canvas 导出A3 PDF与等距网格背景实现方案

一、导出A3尺寸PDF是否需要先定义Canvas为A3尺寸?

不需要直接将用户交互用的Canvas定义为A3尺寸,但导出PDF时必须基于A3规格创建专用的PDF Canvas,并做好绘制内容的缩放适配,具体流程如下:

  1. 保持交互Canvas与屏幕尺寸匹配,让用户正常完成绘制操作,同时将用户绘制的所有路径(Path)或图形数据保存到集合中(比如List<Path>)。
  2. 计算A3尺寸的像素值:A3物理规格为297mm×420mm,若要保证打印清晰度,建议采用300dpi分辨率,计算得像素尺寸为3508×4961;若仅用于屏幕预览,可使用72dpi,对应842×1191。
  3. 创建PDF文档并生成A3页面,将保存的用户绘制内容缩放后绘制到PDF Canvas上:
// 计算A3像素尺寸(300dpi)
val a3WidthMm = 297f
val a3HeightMm = 420f
val dpi = 300f
val widthPx = (a3WidthMm * dpi / 25.4).toInt()
val heightPx = (a3HeightMm * dpi / 25.4).toInt()

// 创建PDF文档
val pdfDocument = PdfDocument()
val pageInfo = PdfDocument.PageInfo.Builder(widthPx, heightPx, 1).create()
val page = pdfDocument.startPage(pageInfo)
val pdfCanvas = page.canvas

// 缩放用户绘制内容到A3尺寸
val viewWidth = yourCustomView.width.toFloat()
val viewHeight = yourCustomView.height.toFloat()
val scaleX = widthPx / viewWidth
val scaleY = heightPx / viewHeight
pdfCanvas.scale(scaleX, scaleY)

// 绘制用户保存的所有路径
val userPaint = Paint().apply {
    color = Color.BLACK
    strokeWidth = 5f
    style = Paint.Style.STROKE
}
yourSavedPaths.forEach { path ->
    pdfCanvas.drawPath(path, userPaint)
}

// 完成PDF生成并保存
pdfDocument.finishPage(page)
pdfDocument.writeTo(FileOutputStream(File(getExternalFilesDir(null), "a3_drawing.pdf")))
pdfDocument.close()

二、实现等距网格背景绘制

等距网格由两组呈60°/120°夹角的平行线交叉构成,可在自定义View的onDraw方法中先绘制网格背景,再叠加用户绘制内容,具体实现:

class IsometricDrawView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
    private val gridPaint = Paint().apply {
        color = Color.parseColor("#E0E0E0")
        strokeWidth = 1f
        style = Paint.Style.STROKE
    }
    private val userPaths = mutableListOf<Path>()
    private val userPaint = Paint().apply {
        color = Color.BLACK
        strokeWidth = 3f
        style = Paint.Style.STROKE
        isAntiAlias = true
    }
    private val gridCellSize = 40f // 网格单元边长,可按需调整

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        // 先绘制等距网格背景
        drawIsometricGrid(canvas)
        // 再绘制用户绘制的路径
        userPaths.forEach { path ->
            canvas.drawPath(path, userPaint)
        }
    }

    private fun drawIsometricGrid(canvas: Canvas) {
        val viewWidth = width.toFloat()
        val viewHeight = height.toFloat()
        val angle60 = Math.toRadians(60.0).toFloat()
        val sin60 = sin(angle60)
        val cos60 = cos(angle60)

        // 绘制第一组平行线(与水平方向成60°)
        var yOffset = 0f
        val stepY = gridCellSize * sin60
        while (yOffset <= viewHeight + stepY) {
            val startX = -yOffset / tan(angle60)
            val endX = viewWidth + (viewHeight - yOffset) / tan(angle60)
            canvas.drawLine(startX, yOffset, endX, viewHeight, gridPaint)
            yOffset += stepY
        }

        // 绘制第二组平行线(与水平方向成120°)
        var xOffset = 0f
        val stepX = gridCellSize * cos60
        while (xOffset <= viewWidth + stepX) {
            val startY = -xOffset * tan(angle60)
            val endY = viewHeight + (viewWidth - xOffset) * tan(angle60)
            canvas.drawLine(xOffset, startY, xOffset, endY, gridPaint)
            xOffset += stepX
        }
    }

    // 添加用户绘制路径的方法
    fun addUserPath(path: Path) {
        userPaths.add(path)
        invalidate()
    }
}

如果View支持滚动,可通过监听滚动偏移量,调整网格绘制的起始坐标,保证网格随滚动连续显示。

内容的提问来源于stack exchange,提问作者Amir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 21:55:12