How to Pass Textfield Value to View Controller Through Button Click in Swift Ui

How to pass Textfield value to view controller through button click in Swift UI

Here is a little sample. Like I said I don't have Google Ads in anything right now but it should be straightforward

import SwiftUI
struct TestAdsView: View {
@StateObject var vm: AdsScreenViewModel = AdsScreenViewModel()
var body: some View {
VStack{
Text(vm.adStatus.rawValue)
TextField("adId", text: $vm.adUnitId)
Button("load Ads", action: {
vm.loadAds()
})
//You might have to play with the position of this.
AdsScreenView_UI(viewModel: vm).frame(width: 0, height: 0)
}
}
}
//This is the source of truth the user input will be held here
class AdsScreenViewModel: ObservableObject, MyAdsViewModelProtocol{
///reference to UIKit
var uiViewController: MyAdsViewControllerProtocol? = nil

@Published var adUnitId: String = ""
@Published var adStatus: AdStatus = .unknown
//MARK: MyAdsViewControllerProtocol
func loadAds() {
print(#function)
uiViewController?.loadAds()
}

func setAdStatus(adStatus: AdStatus) {
print(#function)
self.adStatus = adStatus
}
func getAdId() -> String {
print(#function)
return adUnitId
}

}
struct AdsScreenView_UI: UIViewControllerRepresentable{
@ObservedObject var viewModel: AdsScreenViewModel
func makeUIViewController(context: Context) -> some AdsScreenViewController {
print(#function)
return AdsScreenViewController(viewModel: viewModel)
}

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
print(#function)
}
}
//This can mirror the google sample
class AdsScreenViewController: UIViewController, MyAdsViewControllerProtocol {
///SwiftUI Delegate
var viewModel: MyAdsViewModelProtocol

init(viewModel: MyAdsViewModelProtocol) {
print(#function)
self.viewModel = viewModel
super.init(nibName: nil, bundle: .main)
//Link between UIKit and SwiftUI
self.viewModel.uiViewController = self
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
print(#function)
viewModel.setAdStatus(adStatus: .initialized)
//Put the current code you have here
}
//MARK: MyAdsViewModelProtocol
func loadAds() {
print(#function)
print("ad id \(viewModel.getAdId())")
viewModel.setAdStatus(adStatus: .loading)
//You would load here not in viewDidLoad
}
}
//Protocols aren't needed but it makes the code reusable and you can see the connection protocol = interface
protocol MyAdsViewModelProtocol{
///Reference to the google view controller
var uiViewController: MyAdsViewControllerProtocol? { get set }

///Tells the viewController to load the ad
func loadAds()
///Retrieves the AdId
func getAdId() -> String
///Sets the Ad Status
func setAdStatus(adStatus: AdStatus)
}
protocol MyAdsViewControllerProtocol: UIViewController{
///Reference to the SwiftUI ViewModel
var viewModel: MyAdsViewModelProtocol { get set }
///Tells Google to load the ad
func loadAds()
}
enum AdStatus: String{
case initialized
case loading
case unknown
case error
}

struct TestAdsView_Previews: PreviewProvider {
static var previews: some View {
TestAdsView()
}
}

Sample Image

Return from SwiftUI to Storyboard with a SwiftUI button

A possible approach is to inject a closure with unwind action from a view controller via view model into SwiftUI view and call it inside SwiftUI view button.

Here is main part:

super.init(coder: coder, rootView: SecondView(vm: viewModel))
viewModel.unwind = { [weak self] in
// call unwind segue created in storyboard
self?.performSegue(withIdentifier: "unwind_segue_identifier", sender: self)
}

Complete findings and code here

Call UIKIT function from SWIFTUI

Here is a sample

class UserDashboardModel: ObservableObject {
@Published var totalBalance = 0.0
internal var uIViewController: UserDashboardHostVC? = nil

func getAcctBalance(){
if uIViewController != nil{
uIViewController!.getAcctBalance()
}else{
print("view controller is not connected")
}
}
}
struct UserDashboard: View {

@ObservedObject var userModel: UserDashboardModel
var body: some View{
VStack{
Button(action: {
userModel.getAcctBalance() //Call shared model
}){
Text("Load Balance")
}

Text(userModel.totalBalance.description) //Now it will change
}.frame(width: 400, height: 400, alignment: .center)
}
}
class UserDashboardHostVC: UIViewController {

var userModel = UserDashboardModel()

override func viewDidLoad() {
super.viewDidLoad()
//Crucial connection
userModel.uIViewController = self
let controller = UIHostingController(rootView: UserDashboard(userModel: self.userModel))

self.addChild(controller)
self.view.addSubview(controller.view)
controller.view.translatesAutoresizingMaskIntoConstraints = false
//Update constraints per use case
controller.view.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
controller.view.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
controller.didMove(toParent: self)

}
func getAcctBalance() {
userModel.totalBalance = 599
}
}


Related Topics



Leave a reply



Submit