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

从Composable获取坐标在Canvas绘制RectF位置偏移问题

问题背景

通过.onGloballyPositioned修饰符获取Box组件的布局坐标,实现视图高亮效果,初始坐标获取代码:

val viewLeft = layoutCoordinates.boundsInWindow().left
val viewTop = layoutCoordinates.boundsInWindow().top
val viewRight = layoutCoordinates.boundsInWindow().right
val viewBottom = layoutCoordinates.boundsInWindow().bottom

在Canvas中使用上述坐标绘制高亮圆角矩形时,绘制结果始终存在固定位置偏移,绘制代码如下:

canvas.drawRoundRect(
    viewLeft,
    viewTop,
    viewRight,
    viewBottom,
    cornerRadius,
    cornerRadius,
    paint
)

实际运行效果:
高亮绘制偏移效果

错误原因

核心问题是坐标参考系不匹配:

  • boundsInWindow()返回的是组件相对于整个应用窗口的坐标,原点在窗口左上角
  • Canvas的绘制坐标系原点是Canvas自身的左上角,和窗口原点存在固定偏移,偏移值等于Canvas本身在窗口中的位置坐标
    直接使用窗口坐标系的坐标在Canvas上绘制,就会产生和偏移值完全一致的位置错位。
修复方法

两种方案任选其一即可:

  • 方案1:坐标换算
    给承载绘制逻辑的Canvas也添加.onGloballyPositioned修饰符,拿到Canvas自身在窗口中的位置,将目标Box的窗口坐标转换为Canvas的局部绘制坐标后再绘制:
    // 从Canvas的onGloballyPositioned回调中获取canvasLayoutCoordinates
    val canvasOffsetX = canvasLayoutCoordinates.boundsInWindow().left
    val canvasOffsetY = canvasLayoutCoordinates.boundsInWindow().top
    
    // 换算得到Canvas局部坐标系下的绘制坐标
    val drawLeft = viewLeft - canvasOffsetX
    val drawTop = viewTop - canvasOffsetY
    val drawRight = viewRight - canvasOffsetX
    val drawBottom = viewBottom - canvasOffsetY
    
    canvas.drawRoundRect(
        drawLeft,
        drawTop,
        drawRight,
        drawBottom,
        cornerRadius,
        cornerRadius,
        paint
    )
    
  • 方案2:统一使用父容器参考系
    如果高亮Canvas和目标Box处于同一个父Composable容器下,直接调用layoutCoordinates.boundsInParent()获取Box相对于共同父容器的坐标,只要保证Canvas的布局和Box参考同一个父容器坐标系,直接用该坐标绘制就不会出现偏移。

内容的提问来源于stack exchange,提问作者Ilyas Saleem Khurshid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 11:27:22