I am trying to make a custom UIAlertController with dimmed background which is called by tapping a navigation bar right bar button. My ViewController is embedded in NavigationController and i am expecting my view to cover the whole screen. However, the view is layered either with missing frame if i am adding a subview to navigationController
https://phpout.com/wp-content/uploads/2023/04/IYdKM.png
Or ends up with clear navigation controller if i am adding a subview to ViewController directly
https://phpout.com/wp-content/uploads/2023/04/v0kvL.png
Could you please help me with covering the whole screen? Presenting a ViewController instead of UiView workaround is not fitting in my case.
Here’s the code:
class ToDoViewContoller: UIViewController {
private let toDoListView = ToDoListView()
private let coreDataManager = CoreDataManager()
private let dimmedView = DimmedView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(toDoListView)
setupNavigationBar()
setupConstraints()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
dimmedView.frame = view.bounds
}
private func setupNavigationBar() {
let appearance = UINavigationBarAppearance()
appearance.backgroundColor = .systemIndigo
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.systemBackground]
appearance.titleTextAttributes = [.foregroundColor: UIColor.systemBackground]
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.compactAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
navigationItem.rightBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .add,
target: self,
action: #selector(addButtonTapped))
navigationItem.rightBarButtonItem?.tintColor = .systemBackground
navigationItem.title = "ToDos"
}
@objc private func addButtonTapped() {
view.addSubview(dimmedView)
}
private func setupConstraints() {
NSLayoutConstraint.activate([
toDoListView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
toDoListView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
toDoListView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
toDoListView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
}
2
Answers
Your problem here is that the
dimmedView
is behind the navigation bar. I had ran your code and got thishttps://i.stack.imgur.com/Vsi6k.png
Solution 1: For all dialog or popup, I would prefer to use
UIViewController
rather thanUIView
, and then usepresent(_:animated:completion:)
to present itSolution 2: You can try add subview method above the navigation bar in How to add View above navigation controller?
I simulate your alert UIViews with my fake views because they aren’t in your code, I configure my navigation bar with my extension you can find it here: navigationBar Extension. For your goal you can use additional UIViewCintroller like this example:
In your SceneDelegate set your UINavigationController like that:
After that configure you controller:
This is the result:
When you tap on Add Button, alertVC dismiss itself for now… You can save your CoreData value in the handleAlertDismiss function.
UPDATE based on your comment:
remove closeButtonTap function from your DimmedView, remove closeButton.addTarget(self, action: #selector(closeButtonTap), for: .touchUpInside) from dimmedView. In ToDoViewContoller controller when create UIVievController add call to closeButtonTap function, move out of addButtonTap function constant alertVC and add the closeButtonTap function…
In ToDoViewContoller
In DimmedView class
Now when you tap X close button, alertVC go away…