Last active
November 30, 2023 04:51
-
-
Save mikemike396/4046b65186097a7efe76adcc0d503489 to your computer and use it in GitHub Desktop.
Presenting SwiftUI View inside UINavigationView and communication between both layers.
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
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 | |
} | |
} | |
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
protocol SheetMessageHandler: AnyObject { | |
func applyMessage(message: String) | |
} |
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
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()) | |
} | |
} |
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
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) | |
} | |
} | |
} |
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
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