Skip to content

Commit ababff6

Browse files
authored
Merge pull request #104 from swhitty/backport-canvas
Backport SVGView to iOS 13 / macOS 10.15
2 parents f566120 + d853572 commit ababff6

File tree

3 files changed

+175
-10
lines changed

3 files changed

+175
-10
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//
2+
// CanvasNSView.swift
3+
// SwiftDraw
4+
//
5+
// Created by Simon Whitty on 07/9/25.
6+
// Copyright 2025 Simon Whitty
7+
//
8+
// Distributed under the permissive zlib license
9+
// Get the latest version from here:
10+
//
11+
// https://github.com/swhitty/SwiftDraw
12+
//
13+
// This software is provided 'as-is', without any express or implied
14+
// warranty. In no event will the authors be held liable for any damages
15+
// arising from the use of this software.
16+
//
17+
// Permission is granted to anyone to use this software for any purpose,
18+
// including commercial applications, and to alter it and redistribute it
19+
// freely, subject to the following restrictions:
20+
//
21+
// 1. The origin of this software must not be misrepresented; you must not
22+
// claim that you wrote the original software. If you use this software
23+
// in a product, an acknowledgment in the product documentation would be
24+
// appreciated but is not required.
25+
//
26+
// 2. Altered source versions must be plainly marked as such, and must not be
27+
// misrepresented as being the original software.
28+
//
29+
// 3. This notice may not be removed or altered from any source distribution.
30+
//
31+
32+
#if canImport(AppKit)
33+
import AppKit
34+
import SwiftUI
35+
36+
@available(macOS, deprecated: 12.0, message: "use SwiftUI.Canvas")
37+
struct CanvasFallbackView: NSViewRepresentable {
38+
39+
var svg: SVG
40+
var capInsets: EdgeInsets
41+
var resizingMode: SVGView.ResizingMode
42+
43+
func makeNSView(context: Context) -> CanvasNSView {
44+
let nsView = CanvasNSView()
45+
nsView.wantsLayer = true
46+
nsView.layerContentsRedrawPolicy = .duringViewResize
47+
nsView.layer?.needsDisplayOnBoundsChange = true
48+
return nsView
49+
}
50+
51+
func updateNSView(_ nsView: CanvasNSView, context: Context) {
52+
nsView.svg = svg
53+
nsView.resizeMode = resizingMode
54+
nsView.capInsets = (capInsets.top, capInsets.leading, capInsets.bottom, capInsets.trailing)
55+
nsView.needsDisplay = true
56+
}
57+
}
58+
59+
final class CanvasNSView: NSView {
60+
61+
var svg: SVG?
62+
var resizeMode: SVGView.ResizingMode = .stretch
63+
var capInsets: (top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) = (0, 0, 0, 0)
64+
65+
override var isFlipped: Bool { true }
66+
67+
override func draw(_ dirtyRect: NSRect) {
68+
guard let svg,
69+
let ctx = NSGraphicsContext.current?.cgContext else { return }
70+
71+
ctx.draw(
72+
svg,
73+
in: bounds,
74+
capInsets: capInsets,
75+
byTiling: resizeMode == .tile
76+
)
77+
}
78+
}
79+
80+
#endif
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// CanvasUIView.swift
3+
// SwiftDraw
4+
//
5+
// Created by Simon Whitty on 07/9/25.
6+
// Copyright 2025 Simon Whitty
7+
//
8+
// Distributed under the permissive zlib license
9+
// Get the latest version from here:
10+
//
11+
// https://github.com/swhitty/SwiftDraw
12+
//
13+
// This software is provided 'as-is', without any express or implied
14+
// warranty. In no event will the authors be held liable for any damages
15+
// arising from the use of this software.
16+
//
17+
// Permission is granted to anyone to use this software for any purpose,
18+
// including commercial applications, and to alter it and redistribute it
19+
// freely, subject to the following restrictions:
20+
//
21+
// 1. The origin of this software must not be misrepresented; you must not
22+
// claim that you wrote the original software. If you use this software
23+
// in a product, an acknowledgment in the product documentation would be
24+
// appreciated but is not required.
25+
//
26+
// 2. Altered source versions must be plainly marked as such, and must not be
27+
// misrepresented as being the original software.
28+
//
29+
// 3. This notice may not be removed or altered from any source distribution.
30+
//
31+
32+
#if canImport(UIKit)
33+
import UIKit
34+
import SwiftUI
35+
36+
@available(iOS, deprecated: 15.0, message: "use SwiftUI.Canvas")
37+
struct CanvasFallbackView: UIViewRepresentable {
38+
39+
var svg: SVG
40+
var capInsets: EdgeInsets
41+
var resizingMode: SVGView.ResizingMode
42+
43+
func makeUIView(context: Context) -> CanvasUIView {
44+
let uiView = CanvasUIView()
45+
uiView.isOpaque = false
46+
uiView.contentMode = .redraw
47+
return uiView
48+
}
49+
50+
func updateUIView(_ uiView: CanvasUIView, context: Context) {
51+
uiView.svg = svg
52+
uiView.resizeMode = resizingMode
53+
uiView.capInsets = (capInsets.top, capInsets.leading, capInsets.bottom, capInsets.trailing)
54+
uiView.setNeedsDisplay()
55+
}
56+
}
57+
58+
final class CanvasUIView: UIView {
59+
60+
var svg: SVG?
61+
var resizeMode: SVGView.ResizingMode = .stretch
62+
var capInsets: (top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) = (0, 0, 0, 0)
63+
64+
override func draw(_ rect: CGRect) {
65+
guard let svg,
66+
let ctx = UIGraphicsGetCurrentContext() else { return }
67+
68+
ctx.draw(
69+
svg,
70+
in: rect,
71+
capInsets: capInsets,
72+
byTiling: resizeMode == .tile
73+
)
74+
}
75+
}
76+
77+
#endif

SwiftDraw/Sources/SVGView.swift

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#if canImport(SwiftUI)
3333
public import SwiftUI
3434

35-
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
3635
public struct SVGView: View {
3736

3837
public init(_ name: String, bundle: Bundle = .main) {
@@ -83,17 +82,26 @@ public struct SVGView: View {
8382
return copy
8483
}
8584

85+
@ViewBuilder
8686
private static func makeCanvas(svg: SVG, capInsets: EdgeInsets = .init(), resizingMode: ResizingMode) -> some View {
87-
Canvas(
88-
opaque: false,
89-
colorMode: .linear,
90-
rendersAsynchronously: false
91-
) { ctx, size in
92-
ctx.draw(
93-
svg,
94-
in: CGRect(origin: .zero, size: size),
87+
if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) {
88+
Canvas(
89+
opaque: false,
90+
colorMode: .linear,
91+
rendersAsynchronously: false
92+
) { ctx, size in
93+
ctx.draw(
94+
svg,
95+
in: CGRect(origin: .zero, size: size),
96+
capInsets: capInsets,
97+
byTiling: resizingMode == .tile
98+
)
99+
}
100+
} else {
101+
CanvasFallbackView(
102+
svg: svg,
95103
capInsets: capInsets,
96-
byTiling: resizingMode == .tile
104+
resizingMode: resizingMode
97105
)
98106
}
99107
}

0 commit comments

Comments
 (0)