Skip to content

Instantly share code, notes, and snippets.

@mikemike396
Last active November 30, 2023 04:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikemike396/4046b65186097a7efe76adcc0d503489 to your computer and use it in GitHub Desktop.
Save mikemike396/4046b65186097a7efe76adcc0d503489 to your computer and use it in GitHub Desktop.
Presenting SwiftUI View inside UINavigationView and communication between both layers.
import Combine
import SwiftUI
import UIKit
class SheetHostingViewController: UIViewController {
@IBOutlet var container: UIView!
let viewModel = SheetViewModel()
let alertManager = AlertManager()
weak var messageHandlerDelegate: SheetMessageHandler?
var cancellables = Set<AnyCancellable>()
required init?(coder: NSCoder) {
super.init(coder: coder)
setupObservers()
}
override func viewDidLoad() {
super.viewDidLoad()
let swiftUIView = UIHostingController(rootView: SheetView(viewModel: viewModel))
addChild(swiftUIView)
swiftUIView.view.frame = view.bounds
container.addConstrained(subview: swiftUIView.view)
swiftUIView.didMove(toParent: self)
self.title = "Title"
}
private func setupObservers() {
viewModel.showHUD
.receive(on: DispatchQueue.main)
.sink { [weak self] value in
value ? self?.showHUD() : self?.hideHUD()
}
.store(in: &cancellables)
viewModel.showErrorAlert
.receive(on: DispatchQueue.main)
.sink { [weak self] value in
guard let self else { return }
self.present(self.alertManager.loadingError(), animated: true)
}
.store(in: &cancellables)
viewModel.selectedMessage
.receive(on: DispatchQueue.main)
.sink { [weak self] message in
self?.messageHandlerDelegate?.applyMessage(message: message)
self?.dismiss(animated: true)
}
.store(in: &cancellables)
}
}
extension SheetHostingViewController {
@IBAction func cancelButton(_ sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
}
// MARK: - Protocol Conformances
// MARK: ProgressHUD Functions
extension SheetHostingViewController: ProgressHUDDisplayable {}
// MAKR: - UIView Extension
extension UIView {
func addConstrained(subview: UIView) {
addSubview(subview)
subview.translatesAutoresizingMaskIntoConstraints = false
subview.topAnchor.constraint(equalTo: topAnchor).isActive = true
subview.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
subview.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
subview.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
}
protocol SheetMessageHandler: AnyObject {
func applyMessage(message: String)
}
import Combine
import SwiftUI
struct SheetView: View {
@ObservedObject var viewModel: SheetViewModel
var body: some View {
VStack(spacing: 0) {
list
messageView
}
.padding(.bottom, 20)
}
}
// MARK: Private Views
extension SheetView {
private var list: some View {
List($viewModel.results) { item in
cell(item)
}
.listStyle(.plain)
}
private var messageView: some View {
HStack(spacing: 16) {
TextField("Enter some text", text: $viewModel.message)
.font(weight: .regular, style: .body)
.padding(8)
.overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color(UIColor.separator), style: StrokeStyle(lineWidth: 1.0)))
.onReceive(viewModel.message.publisher.collect()) { value in
let message = String(value.prefix(200))
if viewModel.message != message {
viewModel.message = message
}
}
Button {
Task {
await viewModel.getSuggestedPostText()
}
} label: {
Image("fa_circle-arrow-up")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(maxHeight: 25)
.foregroundColor(Color(.accent))
}
.disabled(viewModel.message.count <= 0)
}
.padding(.horizontal, 20)
}
}
struct SheetView_Previews: PreviewProvider {
static var previews: some View {
SheetView(viewModel: SheetViewModel())
}
}
import Combine
import Foundation
class SheetViewModel: ObservableObject {
// MARK: Published Variables
@Published var message = ""
@Published var results: [String] = []
var selectedMessage = PassthroughSubject<String, Never>()
// MARK: Variables
let showHUD = PassthroughSubject<Bool, Never>()
let showErrorAlert = PassthroughSubject<Bool, Never>()
// MARK: Functions
@MainActor
func getSuggestedPostText() async {
do {
showHUD.send(true)
/// Call API
showHUD.send(false)
} catch {
showHUD.send(false)
showErrorAlert.send(true)
}
}
}
class ViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SheetHostingViewControllerSegue" {
let navigationController = segue.destination as? UINavigationController
if let viewController = navigationController?.viewControllers.first as? SheetHostingViewController {
viewController.messageHandlerDelegate = self
}
}
}
}
extension ViewController: SheetMessageHandler {
func applyMessage(message: String) {
/// Handle Message Selection
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment