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

使用UITouch绘制矩形后截图裁剪位置错误,求正确实现方案

屏幕绘制矩形后截图裁剪位置不正确的问题解决

问题描述

通过UITouch在屏幕绘制矩形并记录坐标,截取全屏截图后按记录的坐标裁剪,结果裁剪位置始终与绘制的矩形不匹配。

核心原因

  1. 坐标系统不匹配:屏幕触摸坐标基于「点(Point)」,而UIImage的CGImage是像素级数据。Retina屏幕下,1个点对应2或3个像素,直接用点坐标裁剪像素级图像会导致位置、尺寸缩放错误。
  2. 旧版截图代码存在兼容性问题:原代码遍历UIApplication.shared.windows的方式在iOS13+已失效,且窗口变换处理可能引入额外坐标偏移。

解决方案

1. 修正裁剪坐标的像素转换

将记录的点坐标乘以截图的scale值,转换为像素坐标后再裁剪:

func cropImage(screenshot: UIImage) -> UIImage {
    let scale = screenshot.scale
    // 把点坐标转为像素坐标
    let cropRect = CGRect(
        x: xCurrent * scale,
        y: yCurrent * scale,
        width: widthCurrent * scale,
        height: heightCurrent * scale
    )
    
    guard let cgImage = screenshot.cgImage?.cropping(to: cropRect) else {
        return screenshot // 裁剪失败返回原图
    }
    // 保留原图的scale和方向,避免图片变形
    return UIImage(cgImage: cgImage, scale: scale, orientation: screenshot.imageOrientation)
}

2. 适配iOS13+的全屏截图代码

改用场景(Scene)获取主窗口,避免旧版API的兼容性问题:

@IBAction func createScreenshot(_ sender: Any) {
    // 获取当前活跃的主窗口
    guard let window = UIApplication.shared.connectedScenes
            .filter({$0.activationState == .foregroundActive})
            .compactMap({$0 as? UIWindowScene})
            .first?.windows
            .first(where: {$0.isKeyWindow}) else {
        return
    }
    
    let imageSize = window.bounds.size
    // 用屏幕scale创建上下文,保证截图清晰度
    UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.main.scale)
    window.drawHierarchy(in: window.bounds, afterScreenUpdates: true)
    let screenshot = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    if let screenshot = screenshot {
        let croppedImage = cropImage(screenshot: screenshot)
        // 后续处理裁剪后的图片(保存/展示等)
    }
}

3. 确保绘制坐标的准确性

如果触摸事件在子视图中处理,需将视图内坐标转换为全局窗口坐标:

// 示例:在UIView的触摸方法中转换坐标
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = touches.first else { return }
    // 将视图本地坐标转为窗口全局坐标
    let windowPoint = touch.location(in: self.window)
    // 调用绘制方法时传入转换后的坐标
    drawSelectionArea(fromPoint: 起始点, toPoint: windowPoint)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:48:24