I created this SwiftUI View:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
MasterView()
}.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
}
struct MasterView: View {
var body: some View {
Form {
Section(header: Text("Geplant")) {
Section {
NavigationLink(destination: /* How can I navigate to a Storyboard ViewController?*/) { Text("Berlin") }
}
}
}
.navigationBarTitle("Wähle Reise")
}
}
As you can read, I want to navigate at line "NavigationLink(destination: .....) to a Storyboard VC.
Before, I navigated to the SwiftUI ContentView using a UIHostingController from a UIKit VC.
Does anyone can help me?
Feel free to ask me for other Code/ Screenshots :)
Use UIViewControllerRepresentable
struct UIKitView: UIViewControllerRepresentable {
typealias UIViewControllerType = UIKitViewController
func makeUIViewController(context: Context) -> UIKitViewController {
let sb = UIStoryboard(name: "Main", bundle: nil)
let viewController = sb.instantiateViewController(identifier: "UIKitViewController") as! UIKitViewController
return viewController
}
func updateUIViewController(_ uiViewController: UIKitViewController, context: Context) {
}
}
And then now use
NavigationLink(destination: UIKitView()) { Text("Berlin") }
Related
I have a UIViewController that I am presenting from a SwiftUI view, previously when presenting from UIKit, I wasn't having this issue. The content at the bottom is being cut off for some reason, how can I fix this?
presented like this from a list:
.fullScreenCover(isPresented: $isPresented, onDismiss: nil, content: {
SingleTakeView(take: take)
})
struct SingleTakeView: UIViewControllerRepresentable {
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
}
var take: TakeOBJ
func makeUIViewController(context: Context) -> UIViewController {
let singleTakeVC = TakeSingleViewController(nibName: "TakeSingleView", bundle: nil, take: take)
let nav = UINavigationController(rootViewController: singleTakeVC)
nav.modalPresentationStyle = .fullScreen
return nav
}
}
You need to set the representable to ignore the safe area. You can either choose .vertical or .bottom.
.fullScreenCover(isPresented: $isPresented, onDismiss: nil, content: {
SingleTakeView(take: take).edgesIgnoringSafeArea(.vertical)
})
I have a UIViewControllerRepresentable like this:
#ObservedObject var viewModel: HomeViewModel
typealias UIViewControllerType = ViewController
func makeUIViewController(context: Context) -> ViewController {
let storyboard = UIStoryboard(name: "ViewController", bundle: Bundle.main)
let viewController = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
// ...
return viewController
}
func updateUIViewController(_ uiViewController: UIKitInboxDetail, context: Context) {
// ...
}
Inside my viewController there is a collectionView.
Now I would like to detect if my collectionView is scrolled and if so perform some actions.
So i've added this method to my ViewController:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if let collectionView = scrollView as? UICollectionView {
isFirstCollectionViewScrolled = true
}
}
But i can access this data only when the view is updated and not at run tiem.
Another approach i've tried is the Coordinator, but I cant perform what I want. Any advice?
Recap: I need to perform some action in my SwiftUI View when a scroll is detected.
Update:
class HomeViewModel: ObservableObject { }
And in my viewController i'm just implementing the usual CollectionView delegates.
If i print somethng in the metod ScrollViewDidEndDegelerating it works! I just neet do something in my swiftUI View when this happened! (A boolean maybe is not the best approach since it set it to true and then it stay true)
I am struggling to hide the navigationBar, which would properly be hidden if the root controller wasn't a SwiftUI UIHostingController.
I tried the following:
Setting navigationController.isNavigationBarHidden = true after creating it, at viewDidLoad and viewWillAppear.
Adding both .navigationBarHidden(true) and .navigationBarBackButtonHidden(true) for the UIHostingController's rootView.
Could it be an Apple bug? I am using Xcode 11.6.
All my attempts together:
class LoginController: UINavigationController, ObservableObject
{
static var newAccount: LoginController
{
let controller = LoginController()
let view = LoginViewStep1()
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
controller.viewControllers = [UIHostingController(rootView: view)]
controller.isNavigationBarHidden = true
return controller
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
self.isNavigationBarHidden = true
}
override func viewDidLoad()
{
super.viewDidLoad()
self.isNavigationBarHidden = true
}
}
struct LoginViewStep1: View
{
// ...
var body: some View
{
VStack {
// ...
}
.navigationBarHidden(true)
.navigationBarBackButtonHidden(true)
}
}
Here is a solution. Tested with Xcode 11.4 / iOS 13.4
Modified your code:
class LoginController: UINavigationController, ObservableObject
{
static var newAccount: LoginController
{
let controller = LoginController()
let view = LoginViewStep1()
controller.viewControllers = [UIHostingController(rootView: view)]
// make it delayed, so view hierarchy become constructed !!!
DispatchQueue.main.async {
controller.isNavigationBarHidden = true
}
return controller
}
}
struct LoginViewStep1: View
{
var body: some View
{
VStack {
Text("Hello World!")
}
}
}
tested part in SceneDelegate
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = LoginController.newAccount
self.window = window
window.makeKeyAndVisible()
}
Alternate solution is to use UINavigationControllerDelegate:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
// Required because pushing UIHostingController makes the navigationBar appear again
navigationController.isNavigationBarHidden = true
}
Tested with iOS 14.5 - Xcode 12.5
I've been testing SwiftUI to see how far I can go with it. Now, I want to find out whether or not I can pass a string from SwiftUI View directly to UIViewController. And I want to display this string with UILabel. UILabel is all I have on my storyoboard.
The following is my view controller (UIViewController).
import UIKit
import SwiftUI
class HomeViewController: UIViewController {
var message = String()
#IBOutlet weak var messageLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
messageLabel.text = message
}
}
struct HomeViewControllerRepresentation: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<HomeViewControllerRepresentation>) -> HomeViewController {
UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "homeViewController") as! HomeViewController
}
func updateUIViewController(_ uiViewController: HomeViewController, context: UIViewControllerRepresentableContext<HomeViewControllerRepresentation>) {
}
}
My SwiftUI View is the following.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: HomeViewControllerRepresentation(message: "GGG")) { // Error
Text("Tap me")
}
}
.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
I hoped that I could just pass a string with HomeViewControllerRepresentation. But it won't work. Is there a simple way of passing data from SwiftUI View to UIViewController? Thanks.
UIViewControllerRepresentable is not a proxy, but wrapper, so everything should be transferred manually, like
struct HomeViewControllerRepresentation: UIViewControllerRepresentable {
var message: String
func makeUIViewController(context: UIViewControllerRepresentableContext<HomeViewControllerRepresentation>) -> HomeViewController {
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "homeViewController") as! HomeViewController
controller.message = self.message
return controller
}
func updateUIViewController(_ uiViewController: HomeViewController, context: UIViewControllerRepresentableContext<HomeViewControllerRepresentation>) {
}
}
I try to use Xcode Preview feature. It works well when I add views directly in code, but if I add any views via storyboard, preview won't show these views. Here is my code:
import UIKit
final class ViewController: UIViewController {
#IBOutlet weak var segmentedControl: UISegmentedControl?
}
#if canImport(SwiftUI) && DEBUG
import SwiftUI
struct ViewControllerRepresentable: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
return ViewController().view
}
func updateUIView(_ view: UIView, context: Context) {
}
}
#available(iOS 13.0, *)
struct ViewController_Preview: PreviewProvider {
static var previews: some View {
Group {
ViewControllerRepresentable()
}
}
}
#endif
That's my controller in simulator and storyboard:
That's how this controller looks in preview:
Set storyboardID (for example "ViewController") for your ViewController in storyboard.
Then create viewController from storyboard
func makeUIView(context: Context) -> UIView {
let viewController = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "ViewController")
return viewController.view
}
Use your storyboard name instead of "Main" if it's different.