Created
January 25, 2020 19:37
-
-
Save marcuswestin/7933f5ee0dceb7be5f49ee75cc035084 to your computer and use it in GitHub Desktop.
An approach for simplified wrapping of AppKit and UIKit view controllers in SwiftUI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// WrappableViewController.swift | |
// macOS-Wordflower | |
// | |
// Created by Marcus Westin on 1/24/20. | |
// Copyright © 2020 Marcus Westin. All rights reserved. | |
// | |
// My preferred approach to wrapping AppKit and UIKit viewControllers in SwiftUI | |
import SwiftUI | |
protocol WrappableViewController: OSViewController { | |
typealias ViewControllerType = Self | |
typealias Context = OSViewControllerRepresentableContext<WrappedViewController<Self>> | |
/// Optional: update view | |
func update(context: Context) | |
/// Optional: wrapped has a functional default implementation and should not | |
/// have to be overriden by protocol implementations | |
var wrapped: WrappedViewController<Self> { get } | |
} | |
// MARK: Default implementations | |
extension WrappableViewController { | |
/// Default empty implementation of optional update function | |
func update(context: Context) {} | |
/// Implementation of wrapped, which should not be overriden by classes | |
internal var wrapped: WrappedViewController<Self> { | |
WrappedViewController { self } | |
} | |
} | |
struct WrappedViewController<Wrappable: WrappableViewController>: OSViewControllerRepresentable { | |
let wrap: () -> Wrappable | |
internal func makeCoordinator() -> Wrappable { | |
return wrap() | |
} | |
#if os(macOS) | |
internal func makeNSViewController(context: NSViewControllerRepresentableContext<WrappedViewController<Wrappable>>) -> Wrappable.ViewControllerType { | |
return context.coordinator | |
} | |
internal func updateNSViewController(_ view: Wrappable.ViewControllerType, context: NSViewControllerRepresentableContext<WrappedViewController<Wrappable>>) { | |
context.coordinator.update(context: context) | |
} | |
#elseif os(iOS) | |
internal func makeUIViewController(context: UIViewControllerRepresentableContext<WrapViewController>) -> Wrapper.ViewControllerType { | |
return context.coordinator | |
} | |
internal func updateUIViewController(_ view: Wrapper.ViewControllerType, context: UIViewControllerRepresentableContext<WrapViewController>) { | |
context.coordinator.update(context: context) | |
} | |
#endif | |
} | |
// MARK: - Example usage | |
struct WrappableViewController_Previews: PreviewProvider { | |
static var previews: some View { | |
Group { | |
ExampleFirstResponderTextField().wrapped | |
ExampleFirstResponderTextField().wrapped | |
} | |
} | |
final class ExampleFirstResponderTextField: NSViewController, WrappableViewController, NSTextFieldDelegate { | |
override func loadView() { | |
let textField = NSTextField(frame: .zero) | |
textField.stringValue = "Hello World!" | |
self.view = textField | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment