ios 13 navigation bar not translucent along with the status bar - ios

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

Related

Ignore Bottom safe area in UIViewController presented from SwiftUI

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

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

Pass data from UIViewControllerRepresentable to SwiftUI

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)

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

How to add Storyboard ViewController into SwiftUI Project?

I am working on my SwiftUI Project and every View is now in SwiftUI, however due to some limitations of SwiftUI I have to add Storyboard's ViewControllers into my SwiftUI project. I am trying this method,
struct AssetsListView: UIViewControllerRepresentable {
var taskID : String
public typealias UIViewControllerType = AssetsListViewController
func makeUIViewController(context: UIViewControllerRepresentableContext<AssetsListView>) -> AssetsListViewController {
let assetsListVC = AssetsListViewController()
assetsListVC.taskID = taskID
return assetsListVC
}
func updateUIViewController(_ uiViewController: AssetsListViewController, context: UIViewControllerRepresentableContext<AssetsListView>) {
}
}
This works fine and even viewDidLoad() method of my Storyboard's ViewController calls, but I am unable to see any element on my Storyboard Screen. How can I render those elements? Just like the normal Storyboard stuff.
You just created controller by class initialiser, to instantiate it from storyboard you have to do like the following
func makeUIViewController(context:
UIViewControllerRepresentableContext<AssetsListView>) -> AssetsListViewController {
let storyboard = UIStoryboard(name: "Main", // < your storyboard name here
bundle: nil)
let assetsListVC = storyboard.instantiateViewController(identifier:
"AssetsListViewController") // < your controller storyboard id here
assetsListVC.taskID = taskID
return assetsListVC
}

Resources