Push ViewController subviews beneath NavigationBar when translucent is True, Programmatically - ios

This question asked to be implemented in Swift 4, iOS 11
Is there any way to make every subview of ViewController's view to be pushed down when it is under UINavigationBar?
If navigation bar is NOT TRANSLUCENT the subview is under it. This is what I want.
Desired Result
But when navigation bar is TRANSLUCENT the subview is lying under it. I dont want it. I want the subview is pushed down just be like if navigation bar is not translucent.
Undesired Result
I create the view programmatically :
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.red
let navBar = (self.parent as? UINavigationController)?.navigationBar
navBar?.isTranslucent = true
}
func makeChildView() {
let myframe = CGRect(x: 0, y: 10, width: self.view.frame.width, height:
self.view.frame.height * 0.4)
let view = UIView(frame: myframe)
view.backgroundColor = UIColor.green
self.view.addSubview(view)
}
Using Autolayout
I am able to solve this problem using autolayout. But I just want to know how to achieve this result without autolayout if possible. Is there any other approach?

Swift 3.x
navBar?.isTranslucent = true
self.automaticallyAdjustsScrollViewInsets = false
Add this line & you are good to go.

Related

Swift 5 custom navigation bar cover title and buttons

After seeking a lot and trying many solutions, nope fixed my problem.
In my app I customized the UINavigationController in order to have blur effect:
import UIKit
class CustomNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
let visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.frame = (self.navigationBar.bounds.insetBy(dx: 0, dy: -40).offsetBy(dx: 0, dy: -40))
self.navigationBar.isTranslucent = true
self.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationBar.addSubview(visualEffectView)
self.navigationBar.sendSubviewToBack(visualEffectView)
}
}
Then in Main.storyboard I selected the customized class for the navigation controller item.
The blur effect works properly, the status icons are correctly visible, but not the standard navigation bar items: left button, title and right button.
For a moment they appears but soon after the customized navigation bar covers them.
I'm using Xcode 12.4 and I'm running the app on iPhone Xr.
How can I show the navigation bar elements again?
Thanks a lot in advance.
Translucent navigation bars in iOS already blur the content behind the bar, so you shouldn't need to add a UIVisualEffectView nor set a backgroundImage.
If you modify your code to just:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationBar.isTranslucent = true
}
does this not achieve the visual effect you're looking for?
If not, please try the following adjustment to your methodology:
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationBar.isTranslucent = true
// create a UIImageView
let backgroundImage: UIImageView = UIImageView()
backgroundImage.autoresizingMask = [.flexibleWidth, .flexibleHeight]
backgroundImage.image = UIImage()
// add a blur effect to the ImageView
let visualEffectView: UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .regular))
visualEffectView.frame = (self.navigationBar.bounds.insetBy(dx: 0, dy: -40).offsetBy(dx: 0, dy: -40))
backgroundImage.addSubview (visualEffectView)
// and set that as your backgroundImage on the navigationBar
self.navigationBar.setBackgroundImage(backgroundImage.image, for: .default)
}
this adds the blur effect to the backgroundImage. This seems to work for me, but the visual effect is no different than just using my first suggestion, likely because backgroundImage.image == nil.
This is certainly an improved approach in that it doesn't add unexpected subviews into the UINavigationBar view hierarchy, and I observed both methods did not affect the visibility of the bar controls.

iOS 13 remove UIView for simulate status bar background

I'm working with a UITableViewController which when scrolling makes the navigationBar disappear. Now when the navigation bar is hidden when the user swipes the table view the contents of the cells are seen below the status bar ...
To solve this problem I tried to insert a UIView to simulate a background of the status bar and everything works but the problem is that when I close the UITableViewController the background view of the status bar is not removed from the superview
For now my code is this, can you help me understand where I am wrong? why can't I remove the UIView from the superview?
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
setupStatusBarView()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
navigationController?.navigationBar.isHidden = true
UIApplication.shared.windows.first?.viewWithTag(1)?.removeFromSuperview()
}
//MARK: - Setup Status Bar View
func setupStatusBarView() {
let height = view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
let statusBarView = UIView()
statusBarView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height:height+5)
statusBarView.backgroundColor = .systemBackground
statusBarView.tag = 1
UIApplication.shared.windows.first?.addSubview(statusBarView)
}
viewDidLayoutSubviews get calls multiple times and you have put setupStatusBarView() in viewDidLayoutSubviews that means your background view has been added multiple times and this is totally wrong flow!
You are removing topmost view only not previous ones!
You should set frame in viewDidLayoutSubviews and should add the view from viewDidLoad!
try this one
let subviewArray = UIApplication.shared.windows.first?.subviews
for view in subviewArray!{
if view.tag == 1{
view.removeFromSuperview()
}
}

How to add imageView down the TabBar in TabBarController

I want to add a imageView below/down the TabBar in TabBarController is there any way to do that. I searched a lot got one answer about adding the TabBarController in other ViewController's container view and add that image down that container view. I also try to add image programmatically but it covers the TabBar.
So how can i do that any suggestion would be appreciated.
Thank You.
Create one custom class inherit it from UITabarController and use the following code
class CustomTabbarController: UITabBarController {
override func loadView() {
super.loadView()
let imageView = UIImageView(frame: CGRect(x: 0, y: self.view.frame.size.height - 10, width: self.view.frame.size.width, height: 10))
imageView.backgroundColor = UIColor.red // set image you wanted to show
self.view.addSubview(imageView)
}
override func viewDidLayoutSubviews() {
tabBar.frame.origin.y = self.view.frame.size.height - 60 // change it according to your requirement
}
}
Now set the custom class to the Tabbarcontroller inside storyboard

iOS - Place an image / container view above navigation bar

For some design purpose, I need to place an image above the navigation bar.
Apple is pretty strict on not changing Nav Bar Height.. and I won't go there.
It's kind of a big app, so I won't have to change each controller apart.
My controllers are mostly presented in nav controllers, so I thought making an extension of UINavigationController will do the trick (so far it does). Anyone have ideas about this ?
extension UINavigationController {
override open func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 11.0, *) {
// This add space under my nav bar
self.additionalSafeAreaInsets = UIEdgeInsets(top: 80, left: 0, bottom: 0, right: 0)
// Need to find a way to move down my nav and add the logo above
}
}
}
The best way for you to place an image is in the Navigation title:
let logo = UIImage(named: "logo.png")
let imageView = UIImageView(image:logo)
self.navigationItem.titleView = imageView
If you want something more customizable, I would suggest you create a View with a 0 constraint with SafeArea.
Add this views in your xib:
And create your navigationController in your class, like this:
import UIKit
class TopLogoViewController: UIViewController {
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let controller = UINavigationController(rootViewController: ViewController())
controller.navigationBar.backgroundColor = .green
controller.navigationBar.barTintColor = .green
controller.navigationBar.shadowImage = UIImage()
controller.navigationBar.isTranslucent = false
addChild(controller)
containerView.addSubview(controller.view)
controller.view.frame = containerView.bounds
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
controller.didMove(toParent: self)
}
}

How to display UIView over keyboard in iOS

I want to create a simple view over keyboard, when users tap "Attach" button in inputAccessoryView.
Something like this:
Is there an easy way to do it? Or i should create my custom keyboard?
You can add that new subview to your application window.
func attach(sender : UIButton)
{
// Calculate and replace the frame according to your keyboard frame
var customView = UIView(frame: CGRect(x: 0, y: self.view.frame.size.height-300, width: self.view.frame.size.width, height: 300))
customView.backgroundColor = UIColor.redColor()
customView.layer.zPosition = CGFloat(MAXFLOAT)
var windowCount = UIApplication.sharedApplication().windows.count
UIApplication.sharedApplication().windows[windowCount-1].addSubview(customView);
}
Swift 4 version:
let customView = UIView(frame: CGRect(x: 0, y: self.view.frame.size.height - 300, width: self.view.frame.size.width, height: 300))
customView.backgroundColor = UIColor.red
customView.layer.zPosition = CGFloat(Float.greatestFiniteMagnitude)
UIApplication.shared.windows.last?.addSubview(customView)
The trick is to add the customView as a top subview to the UIWindow that holds the keyboard - and it happens to be the last window in UIApplication.shared.windows.
Swift 4.0
let customView = UIView(frame: CGRect(x: 0, y: self.view.frame.size.height-300, width: self.view.frame.size.width, height: 300))
customView.backgroundColor = UIColor.red
customView.layer.zPosition = CGFloat(MAXFLOAT)
let windowCount = UIApplication.shared.windows.count
UIApplication.shared.windows[windowCount-1].addSubview(customView)
As Tamás Sengel said, Apple's guidelines does not support adding a view over the keyboard. The recommended way to add a view over keyboard in Swift 4 & 5 is:
1) Add view with your "Next" button in your storyboard as external view and connect in your class (see Explain Image), in my case:
IBOutlet private weak var toolBar: UIView!
2) For the textfield you want to add your custom view over keyboard, add it as accessory view in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
phoneNumberTextField.inputAccessoryView = toolBar
}
3) Add action for "Next" button:
#IBAction func nextButtonPressed(_ sender: Any) {
descriptionTextView.becomeFirstResponder()
// or -> phoneNumberTextField.resignFirstResponder()
}
Explain Image:
Method 2: Result with image
In TableView Controller - add stricked view at bottom
Please follow this great link to handle safe area for screens like iPhone X if you want to use this method(2). Article: InputAccessoryView and iPhone X
override var inputAccessoryView: UIView? {
return toolBar
}
override var canBecomeFirstResponder: Bool {
return true
}
Do you have find some effective method to solve this problem? In iOS9,you put your customView on the top of the windows:
UIApplication.sharedApplication().windows[windowCount-1].addSubview(customView);
But if the keyboard dismisses, the top Windows will be removed, so your customView will be removed.
Looking forward for your help!
Thank you for your help!
You can definitely add the view to your application’s window, and you can also add another window entirely. You can set its frame and level. The level could be UIWindowLevelAlert.
While this can be possible with accessing the topmost window, I would avoid doing this, as it clearly interferes with Apple's guidelines.
What I would do is dismissing the keyboard and replacing its frame with a view with same dimensions.
The keyboard's frame can be accessed from keyboard notifications listed here, their userInfo contain a key that can be accessed with UIKeyboardFrameEndUserInfoKey.

Resources