├── UIViewRepresentableExamples ├── Assets.xcassets │ ├── Contents.json │ ├── stars.dataset │ │ ├── Contents.json │ │ └── stars.svg │ ├── Ghostscript_Tiger.dataset │ │ ├── Contents.json │ │ └── Ghostscript_Tiger.svg │ └── AppIcon.appiconset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── Resources │ └── arnel-hasanovic-4oWSXdeAS2g-unsplash.jpg ├── ContentView.swift ├── Camera │ ├── CameraExample.swift │ ├── CameraPreview.swift │ ├── CameraPreviewWrapperView.swift │ └── DeviceCaptureView.swift ├── TextView │ ├── TextViewExample.swift │ └── TextView.swift ├── HTMLRenderingWebView │ ├── HTMLRenderingWebViewExample.swift │ └── HTMLRenderingWebView.swift ├── ShareSheet │ ├── ShareButton.swift │ ├── ShareExample.swift │ └── ActivityViewControllerWrapper.swift ├── SVGView │ ├── SVGViewExample.swift │ ├── SVGExamples.swift │ └── SVGView.swift ├── ScrollView │ ├── LegacyScrollViewExample.swift │ └── LegacyScrollView.swift ├── AppDelegate.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── Menu.swift ├── MapKit │ ├── MapView.swift │ └── MapKitExample.swift ├── Info.plist ├── Constants.swift └── SceneDelegate.swift ├── screenshots ├── screenshot_svg_small-fs8.png ├── screenshot_mapkit_small-fs8.png ├── screenshot_menu_small-fs8.png └── screenshot_webkit_small-fs8.png ├── UIViewRepresentableExamples.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ └── UIViewRepresentableExamples.xcscheme └── project.pbxproj ├── README.md ├── LICENSE └── .gitignore /UIViewRepresentableExamples/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /screenshots/screenshot_svg_small-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvankuik/UIViewRepresentableExamples/HEAD/screenshots/screenshot_svg_small-fs8.png -------------------------------------------------------------------------------- /screenshots/screenshot_mapkit_small-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvankuik/UIViewRepresentableExamples/HEAD/screenshots/screenshot_mapkit_small-fs8.png -------------------------------------------------------------------------------- /screenshots/screenshot_menu_small-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvankuik/UIViewRepresentableExamples/HEAD/screenshots/screenshot_menu_small-fs8.png -------------------------------------------------------------------------------- /screenshots/screenshot_webkit_small-fs8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvankuik/UIViewRepresentableExamples/HEAD/screenshots/screenshot_webkit_small-fs8.png -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Resources/arnel-hasanovic-4oWSXdeAS2g-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bvankuik/UIViewRepresentableExamples/HEAD/UIViewRepresentableExamples/Resources/arnel-hasanovic-4oWSXdeAS2g-unsplash.jpg -------------------------------------------------------------------------------- /UIViewRepresentableExamples.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ContentView: View { 4 | var body: some View { 5 | Menu() 6 | } 7 | } 8 | 9 | struct ContentView_Previews: PreviewProvider { 10 | static var previews: some View { 11 | ContentView() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Assets.xcassets/stars.dataset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "data" : [ 3 | { 4 | "filename" : "stars.svg", 5 | "idiom" : "universal", 6 | "universal-type-identifier" : "public.svg-image" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Assets.xcassets/Ghostscript_Tiger.dataset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "data" : [ 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Ghostscript_Tiger.svg", 10 | "universal-type-identifier" : "public.svg-image" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Camera/CameraExample.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct CameraExample: View { 4 | var body: some View { 5 | CameraPreview() 6 | .navigationBarTitle("Camera") 7 | } 8 | } 9 | 10 | struct CameraExample_Previews: PreviewProvider { 11 | static var previews: some View { 12 | CameraExample() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UIViewRepresentableExamples 2 | Examples of using UIKit stuff in SwiftUI. 3 | 4 | The examples are not meant to be full-featured. Rather, they're small enough to 5 | quickly understand, but still show enough code so that you can quickly add the 6 | functions your project requires. 7 | 8 | # Screenshots 9 | ![Menu](screenshots/screenshot_menu_small-fs8.png?raw=true) ![Mapkit](screenshots/screenshot_mapkit_small-fs8.png) 10 | 11 | ![SVG](screenshots/screenshot_svg_small-fs8.png?raw=true) ![WebKit](screenshots/screenshot_webkit_small-fs8.png?raw=true) 12 | 13 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/TextView/TextViewExample.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct TextViewExample: View { 4 | @State private var text = "" 5 | 6 | var body: some View { 7 | VStack { 8 | Text("Type something in the box below") 9 | Text("Current count: \(self.text.count)") 10 | TextView(text: self.$text) 11 | .border(Color.gray).padding() 12 | }.navigationBarTitle("UITextView example") 13 | } 14 | } 15 | 16 | struct TextViewExample_Previews: PreviewProvider { 17 | static var previews: some View { 18 | TextViewExample() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/HTMLRenderingWebView/HTMLRenderingWebViewExample.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct HTMLRenderingWebViewExample: View { 4 | @State var htmlString = "" 5 | 6 | var body: some View { 7 | VStack { 8 | HTMLRenderingWebView(htmlString: self.$htmlString, baseURL: .constant(nil)) 9 | .padding(30).background(Color.gray) 10 | Button("Click this button") { 11 | self.htmlString = "

Test

Hello world!" 12 | } 13 | }.navigationBarTitle("Example HTML Rendering") 14 | } 15 | } 16 | 17 | struct HTMLRenderingWebViewExample_Previews: PreviewProvider { 18 | static var previews: some View { 19 | HTMLRenderingWebViewExample() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/ShareSheet/ShareButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShareButton.swift 3 | // UIViewRepresentableExamples 4 | // 5 | // Created by Bart van Kuik on 02/03/2023. 6 | // Copyright © 2023 DutchVirtual. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ShareButton: View { 12 | let url: URL? 13 | 14 | var body: some View { 15 | Text("Tap to share") 16 | .padding() 17 | .border(Color.blue) 18 | .background(Color.yellow) 19 | .overlay(ActivityViewControllerWrapper(url: self.url)) 20 | .accessibilityAddTraits(.isButton) 21 | .accessibilityHint("Share") 22 | } 23 | } 24 | 25 | struct ShareButton_Previews: PreviewProvider { 26 | static var previews: some View { 27 | ShareButton(url: nil) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Camera/CameraPreview.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | // If you would use UIViewRepresentable, and you'd navigate to this view on iPad in landscape, then the orientation 4 | // would be wrong. Thus, we wrap the view in UIViewControllerRepresentable. 5 | 6 | struct CameraPreview: UIViewControllerRepresentable { 7 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIViewController { 8 | let viewController = UIViewController() 9 | viewController.view = CameraPreviewWrapperView() 10 | return viewController 11 | } 12 | 13 | func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext) { 14 | } 15 | } 16 | 17 | struct CameraPreview_Previews: PreviewProvider { 18 | static var previews: some View { 19 | CameraPreview() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/SVGView/SVGViewExample.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct SVGViewExample: View { 4 | @State private var svgString = "" 5 | 6 | var body: some View { 7 | VStack { 8 | SVGView(svgString: self.$svgString) 9 | .border(Color.gray, width: 3) 10 | HStack(spacing: 20) { 11 | Button("Show tiger image") { 12 | self.svgString = SVGExamples.tiger 13 | }.padding() 14 | Button("Show text in oval") { 15 | self.svgString = SVGExamples.smallExample 16 | }.padding() 17 | } 18 | } 19 | } 20 | } 21 | 22 | struct SVGViewExample_Previews: PreviewProvider { 23 | static var previews: some View { 24 | // This won't show anything, you'll have to run a live preview 25 | SVGViewExample() 26 | .previewDevice("iPhone SE") 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/TextView/TextView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct TextView: UIViewRepresentable { 4 | @Binding var text: String 5 | 6 | func makeUIView(context: Context) -> UITextView { 7 | let textView = UITextView() 8 | textView.delegate = context.coordinator 9 | return textView 10 | } 11 | 12 | func updateUIView(_ uiView: UITextView, context: Context) { 13 | uiView.text = text 14 | } 15 | 16 | func makeCoordinator() -> Coordinator { 17 | Coordinator(self) 18 | } 19 | 20 | class Coordinator: NSObject, UITextViewDelegate { 21 | var parent: TextView 22 | 23 | func textViewDidChange(_ textView: UITextView) { 24 | self.parent.text = textView.text 25 | } 26 | 27 | init(_ parent: TextView) { 28 | self.parent = parent 29 | } 30 | }} 31 | 32 | struct TextView_Previews: PreviewProvider { 33 | static var previews: some View { 34 | TextView(text: .constant("Hello world")) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/ScrollView/LegacyScrollViewExample.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ScrollViewContent: View { 4 | @Binding var sampleText: String 5 | 6 | var body: some View { 7 | Text(self.sampleText) 8 | } 9 | } 10 | 11 | struct LegacyScrollViewExample: View { 12 | @State private var action = LegacyScrollView.Action.idle 13 | @State private var sampleText = Constants.lipsum[0] 14 | 15 | var body: some View { 16 | VStack(spacing: 0) { 17 | LegacyScrollView(axis: .vertical, action: self.$action) { 18 | ScrollViewContent(sampleText: self.$sampleText) 19 | } 20 | .padding(20) 21 | .background(Color.gray) 22 | Spacer() 23 | Button("Set offset") { 24 | self.sampleText += Constants.lipsum[0] 25 | }.padding() 26 | }.navigationBarTitle("ScrollView") 27 | } 28 | } 29 | 30 | struct LegacyScrollViewExample_Previews: PreviewProvider { 31 | static var previews: some View { 32 | LegacyScrollViewExample() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 bvankuik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Assets.xcassets/stars.dataset/stars.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/ShareSheet/ShareExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShareExample.swift 3 | // UIViewRepresentableExamples 4 | // 5 | // Created by Bart van Kuik on 02/03/2023. 6 | // Copyright © 2023 DutchVirtual. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ShareExample: View { 12 | static private let imageURL = Bundle.main.url(forResource: "arnel-hasanovic-4oWSXdeAS2g-unsplash", withExtension: "jpg") 13 | private let uiImage: UIImage? = { 14 | // Image by Arnel Hasanovic https://unsplash.com/@arnelhasanovic 15 | guard let url = Self.imageURL else { 16 | return nil 17 | } 18 | guard let data = try? Data(contentsOf: url) else { 19 | return nil 20 | } 21 | return UIImage(data: data) 22 | }() 23 | 24 | var body: some View { 25 | if let uiImage = self.uiImage { 26 | Image(uiImage: uiImage) 27 | ShareButton(url: Self.imageURL) 28 | } else { 29 | EmptyView() 30 | } 31 | } 32 | } 33 | 34 | struct ShareExample_Previews: PreviewProvider { 35 | static var previews: some View { 36 | ShareExample() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Camera/CameraPreviewWrapperView.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import AVFoundation 3 | 4 | class CameraPreviewWrapperView: UIView { 5 | private static func makeLabel(text: String) -> UILabel { 6 | let label = UILabel() 7 | label.adjustsFontForContentSizeCategory = true 8 | label.textAlignment = .center 9 | label.backgroundColor = UIColor.systemGray 10 | label.text = text 11 | label.autoresizingMask = [.flexibleWidth, .flexibleHeight] 12 | return label 13 | } 14 | 15 | override init(frame: CGRect) { 16 | super.init(frame: frame) 17 | 18 | if TARGET_OS_SIMULATOR != 0 { 19 | // We're in simulator, show at least something 20 | self.addSubview(Self.makeLabel(text: "No camera available in simulator")) 21 | } else if AVCaptureDevice.default(for: .video) == nil { 22 | self.addSubview(Self.makeLabel(text: "Camera not found")) 23 | } else { 24 | let deviceCaptureView = DeviceCaptureView() 25 | deviceCaptureView.autoresizingMask = [.flexibleHeight, .flexibleWidth] 26 | self.addSubview(deviceCaptureView) 27 | } 28 | } 29 | 30 | required init?(coder: NSCoder) { 31 | fatalError("init(coder:) has not been implemented") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 9 | // Override point for customization after application launch. 10 | return true 11 | } 12 | 13 | // MARK: UISceneSession Lifecycle 14 | 15 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 16 | // Called when a new scene session is being created. 17 | // Use this method to select a configuration to create the new scene with. 18 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 19 | } 20 | 21 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 22 | // Called when the user discards a scene session. 23 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 24 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 25 | } 26 | 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/HTMLRenderingWebView/HTMLRenderingWebView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import WebKit 3 | 4 | struct HTMLRenderingWebView: UIViewRepresentable { 5 | @Binding var htmlString: String 6 | @Binding var baseURL: URL? 7 | let meta = "" 8 | 9 | func makeUIView(context: Context) -> WKWebView { 10 | let webView = WKWebView() 11 | return webView 12 | } 13 | 14 | func updateUIView(_ uiView: WKWebView, context: Context) { 15 | if self.htmlString != context.coordinator.lastLoadedHTML { 16 | context.coordinator.lastLoadedHTML = self.htmlString 17 | uiView.loadHTMLString(self.meta + self.htmlString, baseURL: self.baseURL) 18 | } 19 | } 20 | 21 | func makeCoordinator() -> Coordinator { 22 | Coordinator(self) 23 | } 24 | 25 | class Coordinator: NSObject { 26 | var parent: HTMLRenderingWebView 27 | var lastLoadedHTML = "" 28 | 29 | init(_ parent: HTMLRenderingWebView) { 30 | self.parent = parent 31 | } 32 | } 33 | } 34 | 35 | struct WebView_Previews: PreviewProvider { 36 | static var previews: some View { 37 | HTMLRenderingWebView(htmlString: .constant("

Test

"), baseURL: .constant(nil)) 38 | .background(Color.gray) 39 | .previewDevice("iPhone 8") 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/SVGView/SVGExamples.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | struct SVGExamples { 4 | // GNU Affero General Public License 5 | // https://commons.wikimedia.org/wiki/File:Ghostscript_Tiger.svg 6 | static var tiger: String = Self.loadAsset(assetName: "Ghostscript_Tiger") 7 | static var stars: String = Self.loadAsset(assetName: "stars") 8 | 9 | static let smallExample = 10 | """ 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | SVG 20 | Sorry, your browser does not support inline SVG. 21 | 22 | """ 23 | 24 | static func loadAsset(assetName: String) -> String { 25 | guard let asset = NSDataAsset(name: assetName) else { 26 | fatalError("Couldn't find SVG in assets, did you actually make a Data Set (not image set) in your xcassets file?") 27 | } 28 | 29 | let data = asset.data 30 | if let string = String(data: data, encoding: .utf8) { 31 | return string 32 | } else { 33 | fatalError("Couldn't turn SVG asset into UTF8 string") 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Menu.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct PadMessage: View { 4 | var body: some View { 5 | Color.clear.overlay ( 6 | GeometryReader { geometry in 7 | Text(geometry.size.width < geometry.size.height 8 | ? "Rotate to see the list of examples" 9 | : "No example selected" 10 | ).font(.headline).foregroundColor(.gray) 11 | } 12 | ) 13 | } 14 | } 15 | 16 | struct Menu: View { 17 | var body: some View { 18 | NavigationView { 19 | List { 20 | NavigationLink(destination: HTMLRenderingWebViewExample()) { 21 | Text("HTML rendering WebView") 22 | } 23 | NavigationLink(destination: MapKitExample()) { 24 | Text("MapKit example") 25 | } 26 | NavigationLink(destination: TextViewExample()) { 27 | Text("TextView example") 28 | } 29 | NavigationLink(destination: LegacyScrollViewExample()) { 30 | Text("LegacyScrollView example") 31 | } 32 | NavigationLink(destination: SVGViewExample()) { 33 | Text("SVG Example") 34 | } 35 | NavigationLink(destination: CameraExample()) { 36 | Text("Camera Example") 37 | } 38 | NavigationLink(destination: ShareExample()) { 39 | Text("Share Example") 40 | } 41 | } 42 | .navigationBarTitle("Available examples") 43 | 44 | PadMessage() 45 | } 46 | } 47 | } 48 | 49 | struct Menu_Previews: PreviewProvider { 50 | static var previews: some View { 51 | Menu() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/ShareSheet/ActivityViewControllerWrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityViewControllerWrapper.swift 3 | // UIViewRepresentableExamples 4 | // 5 | // Created by Bart van Kuik on 02/03/2023. 6 | // Copyright © 2023 DutchVirtual. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct ActivityViewControllerWrapper: UIViewControllerRepresentable { 12 | let url: URL? 13 | 14 | func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIViewController { 15 | let viewController = UIViewController() 16 | let action = UIAction(title: "", image: nil) { action in 17 | let activityViewController = UIActivityViewController(activityItems: [self.url as Any], applicationActivities: nil) 18 | activityViewController.popoverPresentationController?.sourceView = viewController.view // so that iPads won't crash 19 | viewController.present(activityViewController, animated: true, completion: nil) 20 | } 21 | let button = UIButton(frame: .zero, primaryAction: action) 22 | viewController.view = button 23 | 24 | return viewController 25 | } 26 | 27 | func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext) { 28 | } 29 | } 30 | 31 | struct ActivityViewControllerWrapper_Previews: PreviewProvider { 32 | static let url = Bundle.main.url(forResource: "arnel-hasanovic-4oWSXdeAS2g-unsplash", withExtension: "jpg") 33 | 34 | static var previews: some View { 35 | VStack { 36 | Text("Tap to share") 37 | .padding() 38 | .border(Color.blue) 39 | .background(Color.yellow) 40 | .overlay( 41 | ActivityViewControllerWrapper(url: Self.url) 42 | ) 43 | } 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/MapKit/MapView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import MapKit 3 | 4 | struct MapView: UIViewRepresentable { 5 | enum Action { 6 | case idle 7 | case reset(coordinate: CLLocationCoordinate2D) 8 | case changeType(mapType: MKMapType) 9 | } 10 | 11 | @Binding var centerCoordinate: CLLocationCoordinate2D 12 | @Binding var action: Action 13 | 14 | func makeUIView(context: Context) -> MKMapView { 15 | let mapView = MKMapView() 16 | mapView.delegate = context.coordinator 17 | mapView.centerCoordinate = self.centerCoordinate 18 | return mapView 19 | } 20 | 21 | func updateUIView(_ uiView: MKMapView, context: Context) { 22 | switch action { 23 | case .idle: 24 | break 25 | case .reset(let newCoordinate): 26 | uiView.delegate = nil 27 | uiView.centerCoordinate = newCoordinate 28 | DispatchQueue.main.async { 29 | self.centerCoordinate = newCoordinate 30 | self.action = .idle 31 | uiView.delegate = context.coordinator 32 | } 33 | case .changeType(let mapType): 34 | uiView.mapType = mapType 35 | } 36 | } 37 | 38 | func makeCoordinator() -> Coordinator { 39 | Coordinator(self) 40 | } 41 | 42 | class Coordinator: NSObject, MKMapViewDelegate { 43 | var parent: MapView 44 | 45 | func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) { 46 | parent.centerCoordinate = mapView.centerCoordinate 47 | } 48 | 49 | init(_ parent: MapView) { 50 | self.parent = parent 51 | } 52 | } 53 | } 54 | 55 | struct MapView_Previews: PreviewProvider { 56 | static let amsterdamCoordinate = CLLocationCoordinate2D(latitude: 52.37403, longitude: 4.88969) 57 | 58 | static var previews: some View { 59 | MapView(centerCoordinate: .constant(amsterdamCoordinate), action: .constant(.idle)) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | to show an example of a camera 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | UISceneConfigurations 30 | 31 | UIWindowSceneSessionRoleApplication 32 | 33 | 34 | UISceneConfigurationName 35 | Default Configuration 36 | UISceneDelegateClassName 37 | $(PRODUCT_MODULE_NAME).SceneDelegate 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/MapKit/MapKitExample.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import CoreLocation 3 | import MapKit 4 | 5 | extension CLLocationCoordinate2D { 6 | var description: String { 7 | String(format: "%.8f, %.8f", self.latitude, self.longitude) 8 | } 9 | } 10 | 11 | extension MapKitExample { 12 | struct PickerValues { 13 | let mapType: MKMapType 14 | let description: String 15 | } 16 | } 17 | 18 | struct MapKitExample: View { 19 | static let amsterdam = CLLocationCoordinate2D(latitude: 52.37403, 20 | longitude: 4.88969) 21 | @State private var centerCoordinate = Self.amsterdam 22 | @State private var action: MapView.Action = .idle 23 | @State private var mapPickerSelection: Int = 0 24 | 25 | let pickerValues: [PickerValues] = [// [.standard, .hybrid, .satellite] 26 | PickerValues(mapType: .standard, description: "Standard"), 27 | PickerValues(mapType: .hybrid, description: "Hybrid"), 28 | PickerValues(mapType: .satellite, description: "Satellite"), 29 | ] 30 | 31 | var body: some View { 32 | let binding = Binding( 33 | get: { self.mapPickerSelection}, 34 | set: { newValue in 35 | self.action = .changeType(mapType: self.pickerValues[newValue].mapType) 36 | self.mapPickerSelection = newValue 37 | } 38 | ) 39 | return VStack { 40 | MapView(centerCoordinate: self.$centerCoordinate, action: self.$action) 41 | Picker(selection: binding, label: Text("Map type")) { 42 | ForEach(self.pickerValues.indices) { index in 43 | Text(self.pickerValues[index].description).tag(index) 44 | } 45 | }.pickerStyle(SegmentedPickerStyle()) 46 | Text("Centered on: " + self.centerCoordinate.description) 47 | Button("Reset") { 48 | self.action = .reset(coordinate: Self.amsterdam) 49 | } 50 | } 51 | .navigationBarTitle("MapKit Example") 52 | } 53 | } 54 | 55 | struct MapKitExample_Previews: PreviewProvider { 56 | static var previews: some View { 57 | MapKitExample() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Constants.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | struct Constants { 4 | static let lipsum: [String] = [ 5 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", 6 | "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?", 7 | "At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.", 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Camera/DeviceCaptureView.swift: -------------------------------------------------------------------------------- 1 | import AVFoundation 2 | import UIKit 3 | 4 | class DeviceCaptureView: UIView { 5 | private let previewLayer = AVCaptureVideoPreviewLayer() 6 | 7 | private func updateOrientation() { 8 | let orientation: AVCaptureVideoOrientation 9 | switch UIDevice.current.orientation { 10 | case .portrait: 11 | orientation = .portrait 12 | case .landscapeRight: 13 | orientation = .landscapeLeft 14 | case .landscapeLeft: 15 | orientation = .landscapeRight 16 | case .portraitUpsideDown: 17 | orientation = .portraitUpsideDown 18 | case .faceUp: 19 | orientation = .portrait 20 | case .faceDown: 21 | orientation = .portrait 22 | case .unknown: 23 | orientation = .portrait 24 | @unknown default: 25 | fatalError("Unknown orientation") 26 | } 27 | if self.previewLayer.connection?.isVideoOrientationSupported == true { 28 | self.previewLayer.connection?.videoOrientation = orientation 29 | } 30 | self.previewLayer.frame = self.frame 31 | } 32 | 33 | override func layoutSubviews() { 34 | super.layoutSubviews() 35 | self.updateOrientation() 36 | } 37 | 38 | override init(frame: CGRect) { 39 | guard let captureDevice = AVCaptureDevice.default(for: .video) else { 40 | fatalError("Couldn't find default capture device") 41 | } 42 | 43 | guard let captureDeviceInput = try? AVCaptureDeviceInput(device: captureDevice) else { 44 | super.init(frame: frame) 45 | return 46 | } 47 | 48 | let captureSession = AVCaptureSession() 49 | captureSession.addInput(captureDeviceInput) 50 | 51 | self.previewLayer.session = captureSession 52 | self.previewLayer.videoGravity = .resizeAspectFill 53 | 54 | super.init(frame: frame) 55 | 56 | self.layer.addSublayer(self.previewLayer) 57 | self.previewLayer.frame = self.frame 58 | captureSession.startRunning() 59 | } 60 | 61 | required init?(coder: NSCoder) { 62 | fatalError("init(coder:) has not been implemented") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | .DS_Store 92 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import SwiftUI 3 | 4 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | 9 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 10 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 11 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 12 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 13 | 14 | // Create the SwiftUI view that provides the window contents. 15 | let contentView = ContentView() 16 | 17 | // Use a UIHostingController as window root view controller. 18 | if let windowScene = scene as? UIWindowScene { 19 | let window = UIWindow(windowScene: windowScene) 20 | window.rootViewController = UIHostingController(rootView: contentView) 21 | self.window = window 22 | window.makeKeyAndVisible() 23 | } 24 | } 25 | 26 | func sceneDidDisconnect(_ scene: UIScene) { 27 | // Called as the scene is being released by the system. 28 | // This occurs shortly after the scene enters the background, or when its session is discarded. 29 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 30 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 31 | } 32 | 33 | func sceneDidBecomeActive(_ scene: UIScene) { 34 | // Called when the scene has moved from an inactive state to an active state. 35 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 36 | } 37 | 38 | func sceneWillResignActive(_ scene: UIScene) { 39 | // Called when the scene will move from an active state to an inactive state. 40 | // This may occur due to temporary interruptions (ex. an incoming phone call). 41 | } 42 | 43 | func sceneWillEnterForeground(_ scene: UIScene) { 44 | // Called as the scene transitions from the background to the foreground. 45 | // Use this method to undo the changes made on entering the background. 46 | } 47 | 48 | func sceneDidEnterBackground(_ scene: UIScene) { 49 | // Called as the scene transitions from the foreground to the background. 50 | // Use this method to save data, release shared resources, and store enough scene-specific state information 51 | // to restore the scene back to its current state. 52 | } 53 | 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/SVGView/SVGView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import WebKit 3 | 4 | struct SVGView: UIViewRepresentable { 5 | @Environment(\.colorScheme) private var colorScheme 6 | @Binding private var svgString: String 7 | private let darkmodeStyle: String 8 | private let style = 9 | """ 10 | html, body { margin:0; padding:0; overflow:hidden } 11 | :root { 12 | color-scheme: light dark; 13 | } 14 | svg { position:fixed; top:0; left:0; height:100%; width:100%; 15 | } 16 | """ 17 | 18 | private let webView: WKWebView 19 | 20 | func makeUIView(context: Context) -> WKWebView { 21 | return self.webView 22 | } 23 | 24 | func updateUIView(_ uiView: WKWebView, context: Context) { 25 | if self.svgString != context.coordinator.lastLoadedString { 26 | context.coordinator.lastLoadedString = self.svgString 27 | 28 | let htmlString = 29 | "" + 33 | "" + 34 | "" + 35 | self.svgString + 36 | "" 37 | uiView.loadHTMLString(htmlString, baseURL: Bundle.main.bundleURL) 38 | } 39 | } 40 | 41 | func makeCoordinator() -> Coordinator { 42 | Coordinator(self) 43 | } 44 | 45 | class Coordinator: NSObject { 46 | var parent: SVGView 47 | var lastLoadedString = "" 48 | 49 | init(_ parent: SVGView) { 50 | self.parent = parent 51 | } 52 | } 53 | 54 | init(svgString: Binding, darkmodeStyle: String = "") { 55 | let preferences = WKPreferences() 56 | preferences.javaScriptEnabled = false // JavaScript is not needed 57 | let config = WKWebViewConfiguration() 58 | config.preferences = preferences 59 | 60 | let webView = WKWebView(frame: CGRect(), configuration: config) 61 | 62 | webView.isOpaque = false 63 | webView.backgroundColor = .clear 64 | webView.isUserInteractionEnabled = false // to disable pinch gesture and scrolling 65 | self.webView = webView 66 | self._svgString = svgString 67 | self.darkmodeStyle = darkmodeStyle 68 | } 69 | } 70 | 71 | struct SVGView_Previews: PreviewProvider { 72 | static let darkmodeStyle = 73 | """ 74 | svg { 75 | filter: grayscale(100%) invert(100%) brightness(200%); 76 | } 77 | """ 78 | static var previews: some View { 79 | ForEach(ColorScheme.allCases, id: \.self) { 80 | SVGView( 81 | svgString: .constant(SVGExamples.stars), 82 | darkmodeStyle: Self.darkmodeStyle 83 | ) 84 | .preferredColorScheme($0) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples.xcodeproj/xcshareddata/xcschemes/UIViewRepresentableExamples.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/ScrollView/LegacyScrollView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct LegacyScrollView: UIViewRepresentable { 4 | enum Action { 5 | case idle 6 | case offset(x: CGFloat, y: CGFloat, animated: Bool) 7 | } 8 | 9 | let axis: Axis 10 | @Binding var action: Action 11 | private let uiScrollView: UIScrollView 12 | 13 | func makeCoordinator() -> Coordinator { 14 | Coordinator(self) 15 | } 16 | 17 | func makeUIView(context: Context) -> UIScrollView { 18 | return self.uiScrollView 19 | } 20 | 21 | func updateUIView(_ uiView: UIScrollView, context: Context) { 22 | switch self.action { 23 | case .offset(let x, let y, let animated): 24 | uiView.setContentOffset(CGPoint(x: x, y: y), animated: animated) 25 | DispatchQueue.main.async { 26 | self.action = .idle 27 | } 28 | default: 29 | break 30 | } 31 | } 32 | 33 | class Coordinator: NSObject { 34 | let legacyScrollView: LegacyScrollView 35 | 36 | init(_ legacyScrollView: LegacyScrollView) { 37 | self.legacyScrollView = legacyScrollView 38 | } 39 | } 40 | 41 | init(axis: Axis, action: Binding, @ViewBuilder content: () -> Content) { 42 | self.axis = axis 43 | self._action = action 44 | self.uiScrollView = UIScrollView() 45 | 46 | let hosting = UIHostingController(rootView: content()) 47 | hosting.view.translatesAutoresizingMaskIntoConstraints = false 48 | 49 | self.uiScrollView.addSubview(hosting.view) 50 | 51 | let constraints: [NSLayoutConstraint] 52 | switch self.axis { 53 | case .horizontal: 54 | constraints = [ 55 | hosting.view.leadingAnchor.constraint(equalTo: self.uiScrollView.contentLayoutGuide.leadingAnchor), 56 | hosting.view.trailingAnchor.constraint(equalTo: self.uiScrollView.contentLayoutGuide.trailingAnchor), 57 | hosting.view.topAnchor.constraint(equalTo: self.uiScrollView.topAnchor), 58 | hosting.view.bottomAnchor.constraint(equalTo: self.uiScrollView.bottomAnchor), 59 | hosting.view.heightAnchor.constraint(equalTo: self.uiScrollView.heightAnchor) 60 | ] 61 | case .vertical: 62 | constraints = [ 63 | hosting.view.leadingAnchor.constraint(equalTo: self.uiScrollView.leadingAnchor), 64 | hosting.view.trailingAnchor.constraint(equalTo: self.uiScrollView.trailingAnchor), 65 | hosting.view.topAnchor.constraint(equalTo: self.uiScrollView.contentLayoutGuide.topAnchor), 66 | hosting.view.bottomAnchor.constraint(equalTo: self.uiScrollView.contentLayoutGuide.bottomAnchor), 67 | hosting.view.widthAnchor.constraint(equalTo: self.uiScrollView.widthAnchor) 68 | ] 69 | } 70 | self.uiScrollView.addConstraints(constraints) 71 | } 72 | } 73 | 74 | struct LegacyScrollView_Previews: PreviewProvider { 75 | @State static var action = LegacyScrollView.Action.offset(x: 100, y: 0, animated: false) 76 | 77 | static var previews: some View { 78 | LegacyScrollView(axis: .horizontal, action: self.$action) { 79 | Text(Constants.lipsum.joined(separator: "\n\n")) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8924D7DE2458A0B00010C4FE /* CameraExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8924D7DD2458A0B00010C4FE /* CameraExample.swift */; }; 11 | 8924D7E02458A3920010C4FE /* CameraPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8924D7DF2458A3920010C4FE /* CameraPreview.swift */; }; 12 | 8924D7E22458A4CD0010C4FE /* CameraPreviewWrapperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8924D7E12458A4CD0010C4FE /* CameraPreviewWrapperView.swift */; }; 13 | 8924D7E42458A8480010C4FE /* DeviceCaptureView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8924D7E32458A8480010C4FE /* DeviceCaptureView.swift */; }; 14 | 896635EC23E0281500143527 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896635EB23E0281500143527 /* AppDelegate.swift */; }; 15 | 896635EE23E0281500143527 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896635ED23E0281500143527 /* SceneDelegate.swift */; }; 16 | 896635F023E0281500143527 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896635EF23E0281500143527 /* ContentView.swift */; }; 17 | 896635F223E0281600143527 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 896635F123E0281600143527 /* Assets.xcassets */; }; 18 | 896635F523E0281600143527 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 896635F423E0281600143527 /* Preview Assets.xcassets */; }; 19 | 896635F823E0281600143527 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 896635F623E0281600143527 /* LaunchScreen.storyboard */; }; 20 | 8966360023E0298600143527 /* Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 896635FF23E0298600143527 /* Menu.swift */; }; 21 | 8966360323E0359200143527 /* HTMLRenderingWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8966360223E0359200143527 /* HTMLRenderingWebView.swift */; }; 22 | 8966360523E037C500143527 /* HTMLRenderingWebViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8966360423E037C500143527 /* HTMLRenderingWebViewExample.swift */; }; 23 | 8975583023E9A2D500622733 /* LegacyScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8975582F23E9A2D500622733 /* LegacyScrollView.swift */; }; 24 | 8975583223E9A3DD00622733 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8975583123E9A3DD00622733 /* Constants.swift */; }; 25 | 8975583423E9B01100622733 /* LegacyScrollViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8975583323E9B01100622733 /* LegacyScrollViewExample.swift */; }; 26 | 89CAE64223FB1AD100017997 /* SVGViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAE64123FB1AD100017997 /* SVGViewExample.swift */; }; 27 | 89CAE64423FB1B2A00017997 /* SVGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAE64323FB1B2A00017997 /* SVGView.swift */; }; 28 | 89CAE64823FBC55000017997 /* SVGExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CAE64723FBC55000017997 /* SVGExamples.swift */; }; 29 | 89F328DC23E07A7C00B2CB1A /* MapKitExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F328DB23E07A7C00B2CB1A /* MapKitExample.swift */; }; 30 | 89F328DE23E07E7E00B2CB1A /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F328DD23E07E7E00B2CB1A /* MapView.swift */; }; 31 | 89F328E123E0804B00B2CB1A /* TextViewExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F328E023E0804B00B2CB1A /* TextViewExample.swift */; }; 32 | 89F328E323E0808600B2CB1A /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F328E223E0808600B2CB1A /* TextView.swift */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 8924D7DD2458A0B00010C4FE /* CameraExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraExample.swift; sourceTree = ""; }; 37 | 8924D7DF2458A3920010C4FE /* CameraPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreview.swift; sourceTree = ""; }; 38 | 8924D7E12458A4CD0010C4FE /* CameraPreviewWrapperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraPreviewWrapperView.swift; sourceTree = ""; }; 39 | 8924D7E32458A8480010C4FE /* DeviceCaptureView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceCaptureView.swift; sourceTree = ""; }; 40 | 896635E823E0281500143527 /* UIViewRepresentableExamples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIViewRepresentableExamples.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 896635EB23E0281500143527 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 42 | 896635ED23E0281500143527 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 43 | 896635EF23E0281500143527 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 44 | 896635F123E0281600143527 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | 896635F423E0281600143527 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 46 | 896635F723E0281600143527 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 47 | 896635F923E0281600143527 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 896635FF23E0298600143527 /* Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.swift; sourceTree = ""; }; 49 | 8966360223E0359200143527 /* HTMLRenderingWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTMLRenderingWebView.swift; sourceTree = ""; }; 50 | 8966360423E037C500143527 /* HTMLRenderingWebViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HTMLRenderingWebViewExample.swift; sourceTree = ""; }; 51 | 8975582F23E9A2D500622733 /* LegacyScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyScrollView.swift; sourceTree = ""; }; 52 | 8975583123E9A3DD00622733 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; 53 | 8975583323E9B01100622733 /* LegacyScrollViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyScrollViewExample.swift; sourceTree = ""; }; 54 | 89CAE64123FB1AD100017997 /* SVGViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SVGViewExample.swift; sourceTree = ""; }; 55 | 89CAE64323FB1B2A00017997 /* SVGView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SVGView.swift; sourceTree = ""; }; 56 | 89CAE64723FBC55000017997 /* SVGExamples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SVGExamples.swift; sourceTree = ""; }; 57 | 89F328DB23E07A7C00B2CB1A /* MapKitExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapKitExample.swift; sourceTree = ""; }; 58 | 89F328DD23E07E7E00B2CB1A /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; 59 | 89F328E023E0804B00B2CB1A /* TextViewExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewExample.swift; sourceTree = ""; }; 60 | 89F328E223E0808600B2CB1A /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 896635E523E0281500143527 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXFrameworksBuildPhase section */ 72 | 73 | /* Begin PBXGroup section */ 74 | 8924D7DC2458A09F0010C4FE /* Camera */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 8924D7DD2458A0B00010C4FE /* CameraExample.swift */, 78 | 8924D7DF2458A3920010C4FE /* CameraPreview.swift */, 79 | 8924D7E12458A4CD0010C4FE /* CameraPreviewWrapperView.swift */, 80 | 8924D7E32458A8480010C4FE /* DeviceCaptureView.swift */, 81 | ); 82 | path = Camera; 83 | sourceTree = ""; 84 | }; 85 | 896635DF23E0281500143527 = { 86 | isa = PBXGroup; 87 | children = ( 88 | 896635EA23E0281500143527 /* UIViewRepresentableExamples */, 89 | 896635E923E0281500143527 /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | 896635E923E0281500143527 /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 896635E823E0281500143527 /* UIViewRepresentableExamples.app */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | 896635EA23E0281500143527 /* UIViewRepresentableExamples */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 8924D7DC2458A09F0010C4FE /* Camera */, 105 | 89CAE64023FB1AA200017997 /* SVGView */, 106 | 8975582C23E9985400622733 /* ScrollView */, 107 | 89F328DF23E0802A00B2CB1A /* TextView */, 108 | 89F328DA23E07A7000B2CB1A /* MapKit */, 109 | 8966360123E0357700143527 /* HTMLRenderingWebView */, 110 | 896635EB23E0281500143527 /* AppDelegate.swift */, 111 | 896635ED23E0281500143527 /* SceneDelegate.swift */, 112 | 8975583123E9A3DD00622733 /* Constants.swift */, 113 | 896635EF23E0281500143527 /* ContentView.swift */, 114 | 896635FF23E0298600143527 /* Menu.swift */, 115 | 896635F123E0281600143527 /* Assets.xcassets */, 116 | 896635F623E0281600143527 /* LaunchScreen.storyboard */, 117 | 896635F923E0281600143527 /* Info.plist */, 118 | 896635F323E0281600143527 /* Preview Content */, 119 | ); 120 | path = UIViewRepresentableExamples; 121 | sourceTree = ""; 122 | }; 123 | 896635F323E0281600143527 /* Preview Content */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 896635F423E0281600143527 /* Preview Assets.xcassets */, 127 | ); 128 | path = "Preview Content"; 129 | sourceTree = ""; 130 | }; 131 | 8966360123E0357700143527 /* HTMLRenderingWebView */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 8966360223E0359200143527 /* HTMLRenderingWebView.swift */, 135 | 8966360423E037C500143527 /* HTMLRenderingWebViewExample.swift */, 136 | ); 137 | path = HTMLRenderingWebView; 138 | sourceTree = ""; 139 | }; 140 | 8975582C23E9985400622733 /* ScrollView */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 8975583323E9B01100622733 /* LegacyScrollViewExample.swift */, 144 | 8975582F23E9A2D500622733 /* LegacyScrollView.swift */, 145 | ); 146 | path = ScrollView; 147 | sourceTree = ""; 148 | }; 149 | 89CAE64023FB1AA200017997 /* SVGView */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 89CAE64123FB1AD100017997 /* SVGViewExample.swift */, 153 | 89CAE64323FB1B2A00017997 /* SVGView.swift */, 154 | 89CAE64723FBC55000017997 /* SVGExamples.swift */, 155 | ); 156 | path = SVGView; 157 | sourceTree = ""; 158 | }; 159 | 89F328DA23E07A7000B2CB1A /* MapKit */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 89F328DB23E07A7C00B2CB1A /* MapKitExample.swift */, 163 | 89F328DD23E07E7E00B2CB1A /* MapView.swift */, 164 | ); 165 | path = MapKit; 166 | sourceTree = ""; 167 | }; 168 | 89F328DF23E0802A00B2CB1A /* TextView */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 89F328E023E0804B00B2CB1A /* TextViewExample.swift */, 172 | 89F328E223E0808600B2CB1A /* TextView.swift */, 173 | ); 174 | path = TextView; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXGroup section */ 178 | 179 | /* Begin PBXNativeTarget section */ 180 | 896635E723E0281500143527 /* UIViewRepresentableExamples */ = { 181 | isa = PBXNativeTarget; 182 | buildConfigurationList = 896635FC23E0281600143527 /* Build configuration list for PBXNativeTarget "UIViewRepresentableExamples" */; 183 | buildPhases = ( 184 | 896635E423E0281500143527 /* Sources */, 185 | 896635E523E0281500143527 /* Frameworks */, 186 | 896635E623E0281500143527 /* Resources */, 187 | ); 188 | buildRules = ( 189 | ); 190 | dependencies = ( 191 | ); 192 | name = UIViewRepresentableExamples; 193 | productName = UIViewRepresentableExamples; 194 | productReference = 896635E823E0281500143527 /* UIViewRepresentableExamples.app */; 195 | productType = "com.apple.product-type.application"; 196 | }; 197 | /* End PBXNativeTarget section */ 198 | 199 | /* Begin PBXProject section */ 200 | 896635E023E0281500143527 /* Project object */ = { 201 | isa = PBXProject; 202 | attributes = { 203 | LastSwiftUpdateCheck = 1130; 204 | LastUpgradeCheck = 1130; 205 | ORGANIZATIONNAME = DutchVirtual; 206 | TargetAttributes = { 207 | 896635E723E0281500143527 = { 208 | CreatedOnToolsVersion = 11.3.1; 209 | }; 210 | }; 211 | }; 212 | buildConfigurationList = 896635E323E0281500143527 /* Build configuration list for PBXProject "UIViewRepresentableExamples" */; 213 | compatibilityVersion = "Xcode 9.3"; 214 | developmentRegion = en; 215 | hasScannedForEncodings = 0; 216 | knownRegions = ( 217 | en, 218 | Base, 219 | ); 220 | mainGroup = 896635DF23E0281500143527; 221 | productRefGroup = 896635E923E0281500143527 /* Products */; 222 | projectDirPath = ""; 223 | projectRoot = ""; 224 | targets = ( 225 | 896635E723E0281500143527 /* UIViewRepresentableExamples */, 226 | ); 227 | }; 228 | /* End PBXProject section */ 229 | 230 | /* Begin PBXResourcesBuildPhase section */ 231 | 896635E623E0281500143527 /* Resources */ = { 232 | isa = PBXResourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 896635F823E0281600143527 /* LaunchScreen.storyboard in Resources */, 236 | 896635F523E0281600143527 /* Preview Assets.xcassets in Resources */, 237 | 896635F223E0281600143527 /* Assets.xcassets in Resources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | /* End PBXResourcesBuildPhase section */ 242 | 243 | /* Begin PBXSourcesBuildPhase section */ 244 | 896635E423E0281500143527 /* Sources */ = { 245 | isa = PBXSourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | 89CAE64223FB1AD100017997 /* SVGViewExample.swift in Sources */, 249 | 8966360523E037C500143527 /* HTMLRenderingWebViewExample.swift in Sources */, 250 | 8924D7E22458A4CD0010C4FE /* CameraPreviewWrapperView.swift in Sources */, 251 | 89F328DE23E07E7E00B2CB1A /* MapView.swift in Sources */, 252 | 8924D7E02458A3920010C4FE /* CameraPreview.swift in Sources */, 253 | 8966360323E0359200143527 /* HTMLRenderingWebView.swift in Sources */, 254 | 89F328DC23E07A7C00B2CB1A /* MapKitExample.swift in Sources */, 255 | 896635EC23E0281500143527 /* AppDelegate.swift in Sources */, 256 | 89CAE64423FB1B2A00017997 /* SVGView.swift in Sources */, 257 | 896635EE23E0281500143527 /* SceneDelegate.swift in Sources */, 258 | 8966360023E0298600143527 /* Menu.swift in Sources */, 259 | 896635F023E0281500143527 /* ContentView.swift in Sources */, 260 | 89CAE64823FBC55000017997 /* SVGExamples.swift in Sources */, 261 | 8924D7E42458A8480010C4FE /* DeviceCaptureView.swift in Sources */, 262 | 89F328E123E0804B00B2CB1A /* TextViewExample.swift in Sources */, 263 | 89F328E323E0808600B2CB1A /* TextView.swift in Sources */, 264 | 8924D7DE2458A0B00010C4FE /* CameraExample.swift in Sources */, 265 | 8975583023E9A2D500622733 /* LegacyScrollView.swift in Sources */, 266 | 8975583223E9A3DD00622733 /* Constants.swift in Sources */, 267 | 8975583423E9B01100622733 /* LegacyScrollViewExample.swift in Sources */, 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | /* End PBXSourcesBuildPhase section */ 272 | 273 | /* Begin PBXVariantGroup section */ 274 | 896635F623E0281600143527 /* LaunchScreen.storyboard */ = { 275 | isa = PBXVariantGroup; 276 | children = ( 277 | 896635F723E0281600143527 /* Base */, 278 | ); 279 | name = LaunchScreen.storyboard; 280 | sourceTree = ""; 281 | }; 282 | /* End PBXVariantGroup section */ 283 | 284 | /* Begin XCBuildConfiguration section */ 285 | 896635FA23E0281600143527 /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ALWAYS_SEARCH_USER_PATHS = NO; 289 | CLANG_ANALYZER_NONNULL = YES; 290 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 291 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 292 | CLANG_CXX_LIBRARY = "libc++"; 293 | CLANG_ENABLE_MODULES = YES; 294 | CLANG_ENABLE_OBJC_ARC = YES; 295 | CLANG_ENABLE_OBJC_WEAK = YES; 296 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 297 | CLANG_WARN_BOOL_CONVERSION = YES; 298 | CLANG_WARN_COMMA = YES; 299 | CLANG_WARN_CONSTANT_CONVERSION = YES; 300 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 301 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 302 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 303 | CLANG_WARN_EMPTY_BODY = YES; 304 | CLANG_WARN_ENUM_CONVERSION = YES; 305 | CLANG_WARN_INFINITE_RECURSION = YES; 306 | CLANG_WARN_INT_CONVERSION = YES; 307 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 308 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 309 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 310 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 311 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 312 | CLANG_WARN_STRICT_PROTOTYPES = YES; 313 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 314 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 315 | CLANG_WARN_UNREACHABLE_CODE = YES; 316 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 317 | COPY_PHASE_STRIP = NO; 318 | DEBUG_INFORMATION_FORMAT = dwarf; 319 | ENABLE_STRICT_OBJC_MSGSEND = YES; 320 | ENABLE_TESTABILITY = YES; 321 | GCC_C_LANGUAGE_STANDARD = gnu11; 322 | GCC_DYNAMIC_NO_PIC = NO; 323 | GCC_NO_COMMON_BLOCKS = YES; 324 | GCC_OPTIMIZATION_LEVEL = 0; 325 | GCC_PREPROCESSOR_DEFINITIONS = ( 326 | "DEBUG=1", 327 | "$(inherited)", 328 | ); 329 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 330 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 331 | GCC_WARN_UNDECLARED_SELECTOR = YES; 332 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 333 | GCC_WARN_UNUSED_FUNCTION = YES; 334 | GCC_WARN_UNUSED_VARIABLE = YES; 335 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 336 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 337 | MTL_FAST_MATH = YES; 338 | ONLY_ACTIVE_ARCH = YES; 339 | SDKROOT = iphoneos; 340 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 341 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 342 | }; 343 | name = Debug; 344 | }; 345 | 896635FB23E0281600143527 /* Release */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | ALWAYS_SEARCH_USER_PATHS = NO; 349 | CLANG_ANALYZER_NONNULL = YES; 350 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 351 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 352 | CLANG_CXX_LIBRARY = "libc++"; 353 | CLANG_ENABLE_MODULES = YES; 354 | CLANG_ENABLE_OBJC_ARC = YES; 355 | CLANG_ENABLE_OBJC_WEAK = YES; 356 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 357 | CLANG_WARN_BOOL_CONVERSION = YES; 358 | CLANG_WARN_COMMA = YES; 359 | CLANG_WARN_CONSTANT_CONVERSION = YES; 360 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 361 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 362 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 363 | CLANG_WARN_EMPTY_BODY = YES; 364 | CLANG_WARN_ENUM_CONVERSION = YES; 365 | CLANG_WARN_INFINITE_RECURSION = YES; 366 | CLANG_WARN_INT_CONVERSION = YES; 367 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 368 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 369 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 370 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 371 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 372 | CLANG_WARN_STRICT_PROTOTYPES = YES; 373 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 374 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 375 | CLANG_WARN_UNREACHABLE_CODE = YES; 376 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 377 | COPY_PHASE_STRIP = NO; 378 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 379 | ENABLE_NS_ASSERTIONS = NO; 380 | ENABLE_STRICT_OBJC_MSGSEND = YES; 381 | GCC_C_LANGUAGE_STANDARD = gnu11; 382 | GCC_NO_COMMON_BLOCKS = YES; 383 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 384 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 385 | GCC_WARN_UNDECLARED_SELECTOR = YES; 386 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 387 | GCC_WARN_UNUSED_FUNCTION = YES; 388 | GCC_WARN_UNUSED_VARIABLE = YES; 389 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 390 | MTL_ENABLE_DEBUG_INFO = NO; 391 | MTL_FAST_MATH = YES; 392 | SDKROOT = iphoneos; 393 | SWIFT_COMPILATION_MODE = wholemodule; 394 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 395 | VALIDATE_PRODUCT = YES; 396 | }; 397 | name = Release; 398 | }; 399 | 896635FD23E0281600143527 /* Debug */ = { 400 | isa = XCBuildConfiguration; 401 | buildSettings = { 402 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 403 | CODE_SIGN_STYLE = Automatic; 404 | DEVELOPMENT_ASSET_PATHS = "\"UIViewRepresentableExamples/Preview Content\""; 405 | DEVELOPMENT_TEAM = 8LG5SA5X3R; 406 | ENABLE_PREVIEWS = YES; 407 | INFOPLIST_FILE = UIViewRepresentableExamples/Info.plist; 408 | LD_RUNPATH_SEARCH_PATHS = ( 409 | "$(inherited)", 410 | "@executable_path/Frameworks", 411 | ); 412 | PRODUCT_BUNDLE_IDENTIFIER = nl.vankuik.UIViewRepresentableExamples; 413 | PRODUCT_NAME = "$(TARGET_NAME)"; 414 | SWIFT_VERSION = 5.0; 415 | TARGETED_DEVICE_FAMILY = "1,2"; 416 | }; 417 | name = Debug; 418 | }; 419 | 896635FE23E0281600143527 /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 423 | CODE_SIGN_STYLE = Automatic; 424 | DEVELOPMENT_ASSET_PATHS = "\"UIViewRepresentableExamples/Preview Content\""; 425 | DEVELOPMENT_TEAM = 8LG5SA5X3R; 426 | ENABLE_PREVIEWS = YES; 427 | INFOPLIST_FILE = UIViewRepresentableExamples/Info.plist; 428 | LD_RUNPATH_SEARCH_PATHS = ( 429 | "$(inherited)", 430 | "@executable_path/Frameworks", 431 | ); 432 | PRODUCT_BUNDLE_IDENTIFIER = nl.vankuik.UIViewRepresentableExamples; 433 | PRODUCT_NAME = "$(TARGET_NAME)"; 434 | SWIFT_VERSION = 5.0; 435 | TARGETED_DEVICE_FAMILY = "1,2"; 436 | }; 437 | name = Release; 438 | }; 439 | /* End XCBuildConfiguration section */ 440 | 441 | /* Begin XCConfigurationList section */ 442 | 896635E323E0281500143527 /* Build configuration list for PBXProject "UIViewRepresentableExamples" */ = { 443 | isa = XCConfigurationList; 444 | buildConfigurations = ( 445 | 896635FA23E0281600143527 /* Debug */, 446 | 896635FB23E0281600143527 /* Release */, 447 | ); 448 | defaultConfigurationIsVisible = 0; 449 | defaultConfigurationName = Release; 450 | }; 451 | 896635FC23E0281600143527 /* Build configuration list for PBXNativeTarget "UIViewRepresentableExamples" */ = { 452 | isa = XCConfigurationList; 453 | buildConfigurations = ( 454 | 896635FD23E0281600143527 /* Debug */, 455 | 896635FE23E0281600143527 /* Release */, 456 | ); 457 | defaultConfigurationIsVisible = 0; 458 | defaultConfigurationName = Release; 459 | }; 460 | /* End XCConfigurationList section */ 461 | }; 462 | rootObject = 896635E023E0281500143527 /* Project object */; 463 | } 464 | -------------------------------------------------------------------------------- /UIViewRepresentableExamples/Assets.xcassets/Ghostscript_Tiger.dataset/Ghostscript_Tiger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | --------------------------------------------------------------------------------