Ignore Bottom safe area in UIViewController presented from SwiftUI - ios

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)
})

Related

How can I navigate to Storyboard VC from SwiftUI View?

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") }

How to hide UIKit Tabbar in UIViewControllerRepresentable in SwiftUI

I am trying to accessing the Storyboard View Controller in SwiftUI by using UIViewControllerRepresentable. I want to hide the UIKit Tabbar which we applied on ItineraryViewController by using the planDetailViewController.hidesBottomBarWhenPushed = true But that solution not working.
let eventGroup : EventGroup?
func makeUIViewController(context: Context) -> UIViewController {
guard let planDetailViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "ItineraryViewController") as? ItineraryViewController else {
fatalError("ViewController not implemented in storyboard")
}
planDetailViewController.userActionMode = .viewOnly
planDetailViewController.itinerary = eventGroup!.event
planDetailViewController.shouldDisableCalendarVC = true
planDetailViewController.hidesBottomBarWhenPushed = true
return planDetailViewController
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
}
}```
Your UIViewControllerRepresentable won't get pushed into a UINavigationController like in UIKit so hidesBottomBarWhenPushed will not be respected.
The best way to do this is using Introspect like in this answer: https://stackoverflow.com/a/64182729/3393964

Hide UINavigationController's navigationBar when the root controller is a UIHostingController

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

Passing Data from SwiftUI View to UIViewController

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>) {
}
}

ios 13 navigation bar not translucent along with the status bar

I tried to implement my own navigation view in swiftui. But the status appears not translucent as the navigation bar is.
With .edgesIgnoringSafeArea(.top), it worked as I expected.
But i wonder what's wrong with my custom view to make this happen.
struct ExampleNavigationView<Content: View>: UIViewControllerRepresentable {
private var content: () -> Content
init(#ViewBuilder content: #escaping () -> Content){
self.content = content
}
func makeUIViewController(context: Context) -> UINavigationController {
let contentViewController = UIHostingController(rootView: content())
let navigationController = UINavigationController(rootViewController: contentViewController)
navigationController.navigationBar.prefersLargeTitles = false
contentViewController.navigationItem.title = "Search"
return navigationController
}
func updateUIViewController(_ uiViewController: UINavigationController, context: UIViewControllerRepresentableContext<ExampleNavigationView>) {}
}

Resources