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

Xamarin Forms(Android):基于Skiasharp的触摸测试实现方案

实现Xamarin.Forms + SkiaSharp触摸测试自动完成功能

嘿,我来帮你搞定这个自动完成的逻辑!既然已经用SkiaSharp搭好了触摸绘图界面,接下来只需要加一套「框填充状态跟踪+自动检测」的逻辑就行,下面是具体的实现思路和代码示例:

1. 先定义测试框的数据结构

首先得给每个测试框建个“档案”,存它的位置、大小,还有是否被填满的状态——甚至可以加个填充阈值,比如填到80%就算完成,比要求完全填满更灵活:

public class TestBox
{
    public RectF Bounds { get; set; } // 框的位置和尺寸
    public bool IsFilled { get; set; } = false; // 是否已填满
    public float FillThreshold { get; set; } = 0.8f; // 填充达标阈值(0-1)
}

2. 跟踪绘图区域,检测框的填充状态

你应该已经有SKCanvasView的触摸事件处理了,现在要做的是:每次绘图动作结束后,检查每个未填满的框是否被绘制内容覆盖足够面积,然后判断是否所有框都达标。

方案一:精确面积检测(推荐)

用SKRegion计算绘制路径和框的交集面积,判断填充率是否达标,精度很高:

// 假设你用这个列表存所有测试框
private List<TestBox> _testBoxes = new List<TestBox>();
// 假设你用这个路径存用户绘制的所有内容
private SKPath _drawnPath = new SKPath();

// 触摸结束时触发检测
private void OnCanvasViewTouch(object sender, SKTouchEventArgs e)
{
    switch (e.ActionType)
    {
        case SKTouchAction.Released:
            UpdateBoxFillStatus();
            CheckIfAllBoxesFilled();
            break;
        // 你的原有绘图逻辑(比如记录路径点)
        case SKTouchAction.Moved:
            _drawnPath.LineTo(e.Location);
            ((SKCanvasView)sender).InvalidateSurface();
            break;
    }
}

// 更新每个框的填充状态
private void UpdateBoxFillStatus()
{
    foreach (var box in _testBoxes.Where(b => !b.IsFilled))
    {
        // 创建框的区域
        using var boxRegion = new SKRegion();
        boxRegion.SetRect(box.Bounds.ToSKRectI());
        
        // 创建已绘制内容的区域
        using var drawnRegion = new SKRegion();
        drawnRegion.SetPath(_drawnPath, new SKRegion(SKRectI.Infinite));
        
        // 计算两者的交集(即被填充的部分)
        using var intersection = new SKRegion();
        intersection.Intersect(boxRegion, drawnRegion);
        
        // 计算填充率,达标就标记为已填满
        float fillRatio = (float)intersection.Bounds.Area / box.Bounds.Area;
        if (fillRatio >= box.FillThreshold)
        {
            box.IsFilled = true;
        }
    }
}

// 检查是否所有框都已填满,触发完成逻辑
private void CheckIfAllBoxesFilled()
{
    bool allFilled = _testBoxes.All(box => box.IsFilled);
    if (allFilled)
    {
        // 回到主线程更新UI(因为SkiaSharp的触摸事件可能在后台线程)
        Device.BeginInvokeOnMainThread(() =>
        {
            DisplayAlert("测试完成", "所有框都已填满啦!", "确定");
            // 这里可以加你的后续操作,比如提交测试结果、跳转页面等
        });
    }
}

方案二:简化点检测(适合轻量场景)

如果不需要太精确的面积计算,也可以统计框内的触摸点数量,达到一定数量就判定为填满,实现更简单:

private List<SKPoint> _touchPoints = new List<SKPoint>();

private void OnCanvasViewTouch(object sender, SKTouchEventArgs e)
{
    switch (e.ActionType)
    {
        case SKTouchAction.Moved:
            _touchPoints.Add(e.Location);
            ((SKCanvasView)sender).InvalidateSurface();
            break;
        case SKTouchAction.Released:
            UpdateBoxFillStatusWithPoints();
            CheckIfAllBoxesFilled();
            break;
    }
}

private void UpdateBoxFillStatusWithPoints()
{
    foreach (var box in _testBoxes.Where(b => !b.IsFilled))
    {
        // 统计框内的触摸点数量
        int pointsInBox = _touchPoints.Count(p => box.Bounds.Contains(p.X, p.Y));
        // 比如框内有15个点就算填满(可根据框的大小调整)
        if (pointsInBox >= 15)
        {
            box.IsFilled = true;
        }
    }
}

3. 给用户可视化反馈(可选但友好)

可以在PaintSurface方法里给已填满的框加个标记,比如半透明的绿色背景,让用户清楚进度:

private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
    var canvas = e.Surface.Canvas;
    canvas.Clear(SKColors.White);
    
    // 绘制测试框
    var boxStrokePaint = new SKPaint { Color = SKColors.Gray, Style = SKPaintStyle.Stroke, StrokeWidth = 2 };
    var filledBoxFillPaint = new SKPaint { Color = SKColors.LightGreen.WithAlpha(100), Style = SKPaintStyle.Fill };
    
    foreach (var box in _testBoxes)
    {
        if (box.IsFilled)
        {
            canvas.DrawRect(box.Bounds, filledBoxFillPaint);
        }
        canvas.DrawRect(box.Bounds, boxStrokePaint);
    }
    
    // 绘制用户的笔迹
    var drawPaint = new SKPaint { Color = SKColors.Black, Style = SKPaintStyle.Stroke, StrokeWidth = 6, StrokeCap = SKStrokeCap.Round };
    canvas.DrawPath(_drawnPath, drawPaint);
}

小提示

  • 用SKRegion的精确检测性能稍弱,如果测试框很多,建议只在触摸结束后批量检测,别每次触摸移动都跑一遍。
  • 阈值可以根据需求调整,比如要求完全填满就把FillThreshold设为1.0f。
  • 记得在页面销毁时清理SKPaint、SKRegion这些实现了IDisposable的对象,避免内存泄漏。

这样一套逻辑下来,就能实现“所有框填满后自动完成测试”的需求啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:07:01