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

SkiaSharp绘制的矩形在iOS端尺寸小于Android端的问题求助

SkiaSharp iOS端绘制尺寸偏小、布局未铺满问题解决方案

问题根因

  • 尺寸基准错误:使用页面的Width/Height作为计算依据,未使用Skia画布本身的实际绘制区域尺寸,页面尺寸包含了状态栏、导航栏、Grid的Padding、iOS安全区等不属于画布的部分,计算基准本身就存在偏差。
  • 单位不匹配:SkiaSharp默认使用物理像素作为绘制单位,而Xamarin.Forms的Width/Height是逻辑独立像素,iOS设备的缩放因子多为2/3,逻辑像素数值远小于物理像素,直接用逻辑像素计算出的绘制尺寸在物理像素画布上自然会整体偏小。
  • 无效操作引发异常:在PaintSurface事件中修改WidthRequest/HeightRequest会触发布局重测,进而反复触发绘制事件;同时修改数据源Table的宽高属性会引发不必要的属性变更通知,可能导致循环重绘,进一步影响尺寸计算。

修复步骤

1. 优化XAML布局

确保SKCanvasView铺满父容器,不需要手动设置尺寸:

<ContentPage.Content>
    <StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand" BackgroundColor="White">
        <Grid Padding="20">
            <skia:SKCanvasView x:Name="canvasView" 
                           PaintSurface="SKCanvasView_PaintSurface" 
                           BackgroundColor="Beige"
                           HorizontalOptions="FillAndExpand"
                           VerticalOptions="FillAndExpand"/>
        </Grid>
    </StackLayout>
</ContentPage.Content>

2. 修正绘制逻辑

所有尺寸计算基于画布实际像素,删除无效操作:

private void SKCanvasView_PaintSurface(object sender, SkiaSharp.Views.Forms.SKPaintSurfaceEventArgs e)
{
    try
    {
        int NumberColums = 10;
        int NumberRows = 9;
        Size m_CurrentTableSize = new Size();

        var canvas = e.Surface.Canvas;
        // 直接使用画布实际像素尺寸作为计算基准
        var widthView = e.Info.Width;
        var heightView = e.Info.Height;
        m_CurrentTableSize = new Size(widthView / NumberColums, heightView / NumberRows);

        // 绘制前清空画布
        canvas.Clear(SKColors.Beige);

        ObservableCollection<Table> Tables = _viewModel.Tables;

        for (int i = 0; i < Tables.Count; i++)
        {
            Table tableModel = Tables[i];

            int row = tableModel.PositionY;
            int col = tableModel.PositionX;

            int height = tableModel.Height;
            int width = tableModel.Width;

            var dH = (float)m_CurrentTableSize.Height / 68;
            var dW = (float)m_CurrentTableSize.Width / 68;

            var calcRow = (int)(dH * (float)row);
            var calcCol = (int)(dW * (float)col);

            var calcHeight = (int)(height * dH);
            var calcWidth = (int)(width * dW);

            var minSize = Math.Min(calcHeight, calcWidth);

            // 不要修改原数据源的属性,直接用计算值绘制
            canvas.DrawRoundRect(new SKRoundRect(new SKRect((float)calcCol, (float)calcRow, (float)calcCol + (float)minSize, (float)calcRow + (float)minSize)), GetColor(tableModel.Status));
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine(ex);
    }
}

可选优化

如果希望Skia的绘制单位和Xamarin.Forms的逻辑像素保持一致,可以在XAML的SKCanvasView中添加IgnorePixelScaling="True"属性,此时计算尺寸时可以直接使用canvasView.Width和canvasView.Height作为基准。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 18:36:04