Swift make label overlap status bar - swift

I have this label in Swift
let top_error_rep: UILabel = {
let lb = UILabel()
lb.text="Password should be at least 6 charachters"
lb.textColor = UIColor(r: 230, g: 230, b: 230)
lb.backgroundColor = .red
return lb;
}()
I show it only when user input is less than 6 characters. Now when I show it status bar overlaps the input, how can I prevent that?
This is how it looks like

Set label's position.
After you add the label to subViews of your view. You need to set it's position by using constraint like this:
top_error_rep.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
top_error_rep.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
top_error_rep.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
top_error_rep.heightAnchor.constraint(equalToConstant: 20).isActive = true
or you can use different way. Google for Auto layout programmatically swift
Make it only show when user input is less than 6 characters
How do I check when a UITextField changes?
This may helps you
EDIT
add this to your ViewController to hide the status bar
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//Add below line.....
UIApplication.shared.isStatusBarHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
//It will show the status bar again after dismiss
UIApplication.shared.isStatusBarHidden = false
}
override var prefersStatusBarHidden: Bool {
return true
}

Related

Swift: Make the background image of UITableViewController embedded in Navigation Controller fill the entire screen

I managed to create translucent and rounded UITableViewCells in a UITableViewController that is embedded inside a Navigation Controller with this line of code in viewDidLoad():
tableView.backgroundView = UIImageView(image: UIImage(named: "nightTokyo"))
But I want the background image to fill the entire phone screen. I changed the code (and only this line of code) to:
navigationController?.view = UIImageView(image: UIImage(named: "nightTokyo"))
Now the background image fills up the entire phone screen, but my table and even the iPhone's time and battery indicator icons are missing.
What I want is for the background image to fill the entire screen, but the tableView, its cells, the iPhone time, battery level icon, etc. to remain displayed.
navigationController?.setNavigationBarHidden(true, animated: true)
Here is what I did which worked for me using Swift 5, XCode 12.
Step 1 (Optional) - Create a custom UINavigationController class
class CustomNavigationController: UINavigationController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationBar.isTranslucent = true
}
Replace your UINavigationController with this UINavigationController subclass. I mark this as optional as this is based on preference, if you do not set this, your navigation bar will be opaque and you cannot see what's beneath it.
Setting the navigationBar.isTranslucent = true allows you to see the background beneath it which is what I like. A subclass is also optional but you might need to make other updates to your nav bar so I always like to make this a subclass.
Step 2 - Set up your background view constraints
class CustomViewController: UIViewController {
// your background view
let bgImageView: UIImageView = {
let bgImageView = UIImageView()
bgImageView.image = UIImage(named: "gradient_background")
bgImageView.contentMode = .scaleAspectFill
return bgImageView
}()
// Get the height of the nav bar and the status bar so you
// know how far up your background needs to go
var topBarHeight: CGFloat {
var top = self.navigationController?.navigationBar.frame.height ?? 0.0
if #available(iOS 13.0, *) {
top += UIApplication.shared.windows.first?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
} else {
top += UIApplication.shared.statusBarFrame.height
}
return top
}
var isLayoutConfigured = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
title = "Site Visit"
// you only want to do this once
if !isLayoutConfigured() {
isLayoutConfigured = true
configBackground()
}
}
private func configBackground() {
view.addSubview(bgImageView)
configureBackgroundConstraints()
}
// Set up your constraints, main one here is the top constraint
private func configureBackgroundConstraints() {
bgImageView.translatesAutoresizingMaskIntoConstraints = false
bgImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor,
constant: -topBarHeight).isActive = true
bgImageView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor,
constant: 0).isActive = true
bgImageView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor,
constant: 0).isActive = true
bgImageView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor,
constant: 0).isActive = true
view.layoutIfNeeded()
}
Before setting constraints:
After setting above constraints:

Cant change colour of searchBar and it jumps to top of view when selected

I'm trying to attach a search bar to the top of my tableView and change its attributes (eg. colour, placeholder). However, I can't figure out how. I've tried embedding the tableView in another view but that didn't help. Any ideas?
func setupSearch(){
search.delegate = self
search.automaticallyShowsCancelButton = false
search.searchBar.tintColor = UIColor.red
search.searchBar.barTintColor = UIColor.red
search.obscuresBackgroundDuringPresentation = false
search.hidesNavigationBarDuringPresentation = false
search.searchBar.placeholder = "Type something here to search"
navigationItem.searchController = search
tableView.tableHeaderView = search.searchBar
}
This function is called in the viewDidLoad() and the tableView is added but not with the right colour or placeholder and jumps to the top of the screen when selected.
Any help would be appreciated.
This is the updated code for setupSearch (everything is working fine except the bar jumps to the top when selected):
func setupSearch(){
search.delegate = self
search.automaticallyShowsCancelButton = false
search.searchBar.barTintColor = UIColor.red
search.obscuresBackgroundDuringPresentation = false
search.hidesNavigationBarDuringPresentation = false
tableView.tableHeaderView = search.searchBar
}
I declare the search bar at the start using:
let search = UISearchController(searchResultsController: nil)
Any ideas on how to stop the bar jumping to the top?
Just add search bar as tableview's headerview not with navigation's item searchcontroller(not add search bar with both(tableview and navigation) as in your code). You can try with updated code below:
func setupSearch(){
search.delegate = self
search.automaticallyShowsCancelButton = false
search.searchBar.barTintColor = UIColor.red
search.obscuresBackgroundDuringPresentation = false
search.hidesNavigationBarDuringPresentation = false
search.searchBar.placeholder = "Type something here to search"
tableView.tableHeaderView = search.searchBar
self.definesPresentationContext = true
}
override func viewDidLoad() {
super.viewDidLoad()
setupSearch()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil) // be notified when the keyboard changes your table View frame
}
#objc func keyboardWillShow(notification: NSNotification) {
tableView.frame.origin.y = 0 // reset the table view to its original coordinates
}
func setupSearch(){
// for iOS 12 and lower, you can change the placeholder like this :
let textFieldSearchBar = searchBar.value(forKey: "searchField") as? UITextField
textFieldSearchBar?.textColor = .red
let searchBarLabel = textFieldSearchBar!.value(forKey: "placeholderLabel") as? UILabel
textFieldSearchBarLabel?.textColor = .red
}

How to change Navigation Bar back to translucent after making it transparent

I have a view controller in my navigation stack that needs to have a transparent navigation bar, while still showing the back button.
I'm able to achieve that with one line of code inside viewWillAppear:
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
However, when I try to go back to the previous view, I'm setting the background image back to nil or .none but I'm losing the translucent effect that was previously on there when I do that.
I've tried setting all the following options in viewWillDisappear and none seem to bring the translucency back. It just appears white no matter what I do. The shadow on the bottom is also gone too:
self.navigationController?.navigationBar.isTranslucent = true
self.navigationController?.navigationBar.barStyle = .default
self.navigationController?.navigationBar.backgroundColor = .none
self.navigationController?.navigationBar.setBackgroundImage(.none, for: .default)
Initial Navigation Bar:
Transparent Navigation Bar:
After Transitioning Back:
In viewWillAppear make the navigation bar transparent
override func viewWillAppear(_ animated: Bool) { self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = true
}
And backg to translucent in viewWillDisappear
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.shadowImage = nil
self.navigationController?.navigationBar.isTranslucent = false
}
After spending time poking around in the UINavigationBar internals, I did discover a simple method that seems to work, and does not require any configuration of the standard UINavigationBar attributes we've previously fiddled with to achieve transparency. The following is tested working on iOS 12.2.x:
class TallNavigationBar: UINavigationBar {
private lazy var maskingView: UIView = {
let view = UIView(frame: bounds)
view.backgroundColor = .clear
return view
}()
var isTransparent = false {
didSet {
guard isTransparent != oldValue, let bkgView = subviews.first else { return }
bkgView.mask = isTransparent ? maskingView : nil
}
}
}
Obviously, whenever fiddling (even slightly) with undocumented internals: use at your own risk!
This worked for my app which needs to revert to an opaque navigation bar after popping from a transparent navigation bar.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
navigationController?.navigationBar.shadowImage = nil
navigationController?.navigationBar.isTranslucent = true
navigationController?.navigationBar.backgroundColor = nil
}

TableView Content behind TabBar

I've searched through S/OF and can't find a fix for the TableView being behind my TabBar.
I set up my TableView like this;
func setUpTableView() {
messagesTableView.frame = view.frame
messagesTableView.backgroundColor = .white
view.addSubview(messagesTableView)
messagesTableView.tableFooterView = UIView()
messagesTableView.delegate = self
messagesTableView.dataSource = self
messagesTableView.register(UITableViewCell.self, forCellReuseIdentifier: messagesCellIdentifier)
edgesForExtendedLayout = []
extendedLayoutIncludesOpaqueBars = false
messagesTableView.contentInsetAdjustmentBehavior = .never
}
Then I setUpTableView() in viewDidLoad().
According to all sources
edgesForExtendedLayout = []
extendedLayoutIncludesOpaqueBars = false
messagesTableView.contentInsetAdjustmentBehavior = .never
Should satisfy the content insets and not allow the TableView to scroll behind the TabBar.
Please note my TabBars' translucency is set to false inside TabBarController.
tabBar.isTranslucent = false
As always any help appreciated.
Adding Illustration
When scrolling to the bottom is not showing the complete TableView content as the TabBar covers the last few indexes.
Did you try this in viewDidAppear ?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
Edit
Remove
messagesTableView.frame = view.frame
and add autoLayout to your messagesTableView
messagesTableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
messagesTableView.topAnchor.constraint(equalTo: topAnchor),
messagesTableView.leftAnchor.constraint(equalTo: leftAnchor),
messagesTableView.bottomAnchor.constraint(equalTo: bottomAnchor),
messagesTableView.rightAnchor.constraint(equalTo: rightAnchor)
])

Set textfield in UISearchBar

I'm trying to add SearchController to UINavigationBar. I'm trying to set UITextField of UISearchBar after back button of UINavigationController. I want some more space after back button
When I start searching it appears as
Whereas I should be able to view back button. Only textfield width should be decreased. Also after Cancel it should be again back to initial layout. Whereas it is displayed as below:
Below is my code
var searchResultController = UISearchController()
self.searchResultController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.searchBar.sizeToFit()
controller.searchBar.delegate = self
controller.hidesNavigationBarDuringPresentation = false
self.navigationController?.navigationBar.addSubview(controller.searchBar)
return controller
})()
override func viewDidAppear(animated: Bool) {
for subView in searchResultController.searchBar.subviews{
for subsubView in subView.subviews {
if let textField = subsubView as? UITextField {
var bounds: CGRect
bounds = textField.frame
bounds.size.width = self.view.bounds.width - 50
}
}
}
}
Please let me know how can I fix this.
Thanks in advance
For setting the UIsearchBar add it to Navigation's titleView as
self.navigationItem.titleView = controller.searchBar
For removing Cancel button we can use UISearchControllerDelegate method
func didPresentSearchController(searchController: UISearchController) {
searchController.searchBar.showsCancelButton = false
}
Hope this may help any one.