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