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

SwiftUI:缩放UIBezierPath生成的Image以适配父视图

解决跑步路线轨迹UIBezierPath适配父视图的问题

要让生成的跑步路线图完整适配父视图不被裁剪,核心是动态计算路径的缩放比例和偏移量,替代原代码中的固定缩放值。以下是修改后的完整实现:

struct WorkoutRoutePathForCard: View {
    
    @State var coords: [CLLocationCoordinate2D]
    
    var body: some View {
        VStack {
            GeometryReader { geometry in
                Image(uiImage: getPathImage(targetSize: geometry.size, coordinates: coords))
                    .resizable()
                    .scaledToFit()
            }
        }
        .frame(width: 300, height: 300)
    }
    
    func getPathImage(targetSize: CGSize, coordinates: [CLLocationCoordinate2D]) -> UIImage {
        let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
        let renderer = MKPolylineRenderer(polyline: polyline)
        guard let path = renderer.path else { return UIImage() }
        
        let bezierPath = UIBezierPath(cgPath: path)
        let pathBounds = bezierPath.bounds
        
        // 计算缩放比例:留出5%的边距,取宽高比例的最小值
        let scaleWidth = (targetSize.width * 0.9) / pathBounds.width
        let scaleHeight = (targetSize.height * 0.9) / pathBounds.height
        let scale = min(scaleWidth, scaleHeight)
        
        // 计算偏移量,让路径居中
        let offsetX = (targetSize.width - pathBounds.width * scale) / 2 - pathBounds.minX * scale
        let offsetY = (targetSize.height - pathBounds.height * scale) / 2 - pathBounds.minY * scale
        
        // 应用缩放和平移变换
        let transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: offsetX, y: offsetY)
        bezierPath.apply(transform)
        
        // 渲染图像
        let imageRenderer = UIGraphicsImageRenderer(bounds: CGRect(origin: .zero, size: targetSize))
        return imageRenderer.image { context in
            UIColor.clear.setFill()
            context.fill(CGRect(origin: .zero, size: targetSize))
            
            UIColor.green.setStroke()
            bezierPath.lineWidth = 5
            bezierPath.stroke()
        }
    }
}

// 示例坐标
let myCoords: [CLLocationCoordinate2D] = [
    .init(latitude: 40.45447016031924, longitude: -79.98049149097986),
    .init(latitude: 40.45480813412811, longitude: -79.98042319697163),
    .init(latitude: 40.45520567452709, longitude: -79.98001536452354),
    .init(latitude: 40.455495507707624, longitude: -79.97960818847154),
    .init(latitude: 40.455669734914764, longitude: -79.97945181240351),
    .init(latitude: 40.455962469448195, longitude: -79.97968629102485),
    .init(latitude: 40.45610586081772, longitude: -79.97963772295147),
    .init(latitude: 40.4562591381994, longitude: -79.97981354297161),
    .init(latitude: 40.45641915652463, longitude: -79.98013725326828),
    .init(latitude: 40.456916076807275, longitude: -79.98057473087967),
    .init(latitude: 40.45696543637191, longitude: -79.98111241962415),
    .init(latitude: 40.45658094060211, longitude: -79.9815750340419),
    .init(latitude: 40.45633241325463, longitude: -79.98213689422677),
    .init(latitude: 40.456005715732466, longitude: -79.98264837678823),
    .init(latitude: 40.45566308287974, longitude: -79.98313926160685),
    .init(latitude: 40.455482156946836, longitude: -79.98339909382858),
    .init(latitude: 40.455431346304245, longitude: -79.98350236725716),
    .init(latitude: 40.45510882284016, longitude: -79.98392447563586),
    .init(latitude: 40.45473960595957, longitude: -79.983839249276),
    .init(latitude: 40.45419535436064, longitude: -79.98372212671902),
    .init(latitude: 40.45418877882902, longitude: -79.98317032323045),
    .init(latitude: 40.45409625179924, longitude: -79.98337238791783),
    .init(latitude: 40.453702136321205, longitude: -79.98383112841569),
    .init(latitude: 40.45333968007657, longitude: -79.9843527839287),
    .init(latitude: 40.453015767532904, longitude: -79.98470010009864),
    .init(latitude: 40.452756328441005, longitude: -79.98519113714033),
    .init(latitude: 40.452431463269576, longitude: -79.98567567972282),
    .init(latitude: 40.45211699883118, longitude: -79.98613715996406),
    .init(latitude: 40.45180291771363, longitude: -79.98659016559115),
    .init(latitude: 40.45130420151201, longitude: -79.98645138634363),
    .init(latitude: 40.450950946065355, longitude: -79.98694918550348),
    .init(latitude: 40.4506422698389, longitude: -79.98745765702658),
    .init(latitude: 40.450327618934, longitude: -79.98798683271804),
    .init(latitude: 40.449992148160234, longitude: -79.98850139382195),
    .init(latitude: 40.449618449168355, longitude: -79.98819580017779),
    .init(latitude: 40.44961717175458, longitude: -79.98813056857591),
    .init(latitude: 40.44981214587717, longitude: -79.98784037287729),
    .init(latitude: 40.45010798888214, longitude: -79.98731732932961),
    .init(latitude: 40.45044357521365, longitude: -79.98682415678626),
    .init(latitude: 40.45074079718418, longitude: -79.9863306116891),
    .init(latitude: 40.45102708900798, longitude: -79.9858412709496),
    .init(latitude: 40.45135186368611, longitude: -79.98537165274894),
    .init(latitude: 40.451693905584776, longitude: -79.98487831686919),
    .init(latitude: 40.451695266189674, longitude: -79.9846134771703),
    .init(latitude: 40.4519948921123, longitude: -79.98410232215397),
    .init(latitude: 40.45211625978421, longitude: -79.9836457603929),
    .init(latitude: 40.4517601191445, longitude: -79.98325242116834),
    .init(latitude: 40.45199766696091, longitude: -79.98257604896489),
    .init(latitude: 40.452354714382864, longitude: -79.98217790736636),
    .init(latitude: 40.452722542943405, longitude: -79.98175806857729),
    .init(latitude: 40.453023655083086, longitude: -79.98131890493468),
    .init(latitude: 40.453351081755606, longitude: -79.98081647794157),
    .init(latitude: 40.453523684592156, longitude: -79.98081191524473),
    .init(latitude: 40.45386406976813, longitude: -79.9812629401123),
    .init(latitude: 40.45418688545403, longitude: -79.98132777596072)
]

关键修改说明

  1. 动态计算缩放比例:
    • 获取路径的原始边界框pathBounds,对比目标视图的尺寸,计算出能让路径完整显示的最大缩放比例,同时留出90%的视图空间(避免边缘紧贴)。
  2. 居中偏移计算:
    • 计算偏移量让缩放后的路径在目标视图中完全居中,避免路径偏移到视图外被裁剪。
  3. 修正渲染边界:
    • 渲染图像时使用目标视图的完整尺寸作为边界,不再设置偏移的bounds,确保生成的图像刚好填满视图。
  4. 优化Image显示:
    • 给Image添加.resizable()和.scaledToFit(),进一步确保图像在SwiftUI视图中正确适配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 15:10:23