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) ]
关键修改说明
- 动态计算缩放比例:
- 获取路径的原始边界框
pathBounds,对比目标视图的尺寸,计算出能让路径完整显示的最大缩放比例,同时留出90%的视图空间(避免边缘紧贴)。
- 获取路径的原始边界框
- 居中偏移计算:
- 计算偏移量让缩放后的路径在目标视图中完全居中,避免路径偏移到视图外被裁剪。
- 修正渲染边界:
- 渲染图像时使用目标视图的完整尺寸作为边界,不再设置偏移的bounds,确保生成的图像刚好填满视图。
- 优化Image显示:
- 给Image添加
.resizable()和.scaledToFit(),进一步确保图像在SwiftUI视图中正确适配。
- 给Image添加
内容的提问来源于stack exchange,提问作者GarySabo
相关产品推荐
相关产品推荐

