How to set navigation controller settings only one time - swift

In my swift app I've many navigation controller and for each of them I want to set this settings:
navigationController?.navigationBar.backIndicatorImage = #imageLiteral(resourceName: "backArrow").withRenderingMode(.automatic)
navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "backArrow")
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem?.tintColor = UIColor(red: 235/255, green: 235/255, blue: 235/255, alpha: 1)
How can I set this settings only one time, I mean without write this code for each class?

Create a BaseViewController like
class BaseViewConroller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
navSetting()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func navSetting() {
navigationController?.navigationBar.backIndicatorImage = #imageLiteral(resourceName: "backArrow").withRenderingMode(.automatic)
navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(named: "backArrow")
navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style:
.plain, target: nil, action: nil)
navigationItem.backBarButtonItem?.tintColor = UIColor(red: 235/255, green: 235/255, blue: 235/255, alpha: 1)
}
}
You can create all your view controller like
class HomeViewController: BaseViewConroller {
...
}

Related

UIAlertController Alert action TextField need to be resized-error

Getting this error...
[LayoutConstraints] Changing the translatesAutoresizingMaskIntoConstraints property of a UICollectionViewCell that is managed by a UICollectionView is not supported, and will result in incorrect self-sizing. View: <_UIAlertControllerTextFieldViewCollectionCell: 0x7fe6a9f26000; frame = (0 0; 270 24); gestureRecognizers = <NSArray: 0x60000098edc0>; layer = <CALayer: 0x6000007c5cc0>>
From this...
func saveText()
{
let ac = UIAlertController(title: "NAME IT", message: nil, preferredStyle: .alert)
ac.addTextField()
let submitAction = UIAlertAction(title: "SAVE", style: .default)
{
[unowned ac] _ in
let answer = ac.textFields![0]
if answer.text!.count < 1
{
self.view.backgroundColor = .red
}
else
{
self.view.backgroundColor = .green
}
}
ac.addAction(submitAction)
present(ac, animated: true)
}
I have played around with this for a while, I have tried to figure out if I can add my own textfield to use it too...
func addTextField()
{
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
}
But no luck
I need to remove this error.
Thanks in advance
Oh, this didn't help at all
https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-uitextfield-to-a-uialertcontroller
Thanks for trying to help, couldn't waste more than a day waiting for a solution so I spent two hours on a workaround instead.
I figured it would be mean of me not to share...
OR rather nice that I spent the extra 20 mins to share my workaround.
If anyone plays hero and wants to edit this, I am happy to delete the answer.
import UIKit
class ViewController: UIViewController
{
let textFieldView = UIView()
let textFieldLabel = UILabel()
let textFieldField = UITextField()
let textFieldButton = UIButton()
let WhiteUIColour: UIColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
let LightGreyUIColour: UIColor = #colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1)
let DarkBlueUIColour: UIColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 1)
let MediumGreyCGColour: CGColor = #colorLiteral(red: 0.7540688515, green: 0.7540867925, blue: 0.7540771365, alpha: 1)
let bold17 = UIFont.boldSystemFont(ofSize: 17)
let hel17 = UIFont (name: "Helvetica", size: 17)
let hel20 = UIFont (name: "Helvetica", size: 20)
// Create button to present the UIAlert with textField workaround view
let yourButton = UIButton()
func createYourButton()
{
view.addSubview(yourButton)
yourButton.translatesAutoresizingMaskIntoConstraints = false
yourButton.backgroundColor = .red
yourButton.setTitle("TAP ME", for: .normal)
yourButton.addTarget(self, action: #selector(saveButtonTap), for: .touchUpInside)
NSLayoutConstraint.activate([
yourButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
yourButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
yourButton.widthAnchor.constraint(equalToConstant: 100),
yourButton.heightAnchor.constraint(equalToConstant: 50),
])
}
#objc func saveButtonTap()
{
saveName()
}
func saveName()
{
textfieldUIAlert()
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200), execute:
{
self.textFieldView.isHidden = false
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute:
{
self.textFieldField.becomeFirstResponder()
})
})
}
func textfieldUIAlert()
{
view.addSubview(textFieldView)
textFieldView.isHidden = true
textFieldView.translatesAutoresizingMaskIntoConstraints = false
textFieldView.backgroundColor = LightGreyUIColour
textFieldView.layer.cornerRadius = 16
textFieldView.addSubview(textFieldLabel)
textFieldLabel.translatesAutoresizingMaskIntoConstraints = false
textFieldLabel.textAlignment = .center
textFieldLabel.font = bold17
textFieldLabel.text = "NAME IT"
textFieldView.addSubview(textFieldField)
textFieldField.translatesAutoresizingMaskIntoConstraints = false
textFieldField.backgroundColor = WhiteUIColour
textFieldField.layer.borderColor = MediumGreyCGColour
textFieldField.layer.borderWidth = 0.5
textFieldField.layer .cornerRadius = 9
textFieldField.font = hel20
textFieldField.textAlignment = .center
textFieldView.addSubview(textFieldButton)
textFieldButton.translatesAutoresizingMaskIntoConstraints = false
textFieldButton.setTitleColor(DarkBlueUIColour, for: .normal)
textFieldButton.titleLabel?.font = hel17
textFieldButton.setTitle("SAVE", for: .normal)
textFieldButton.addTarget(self, action: #selector(textFieldButtonTap), for: .touchUpInside)
NSLayoutConstraint.activate([
textFieldView.topAnchor.constraint(equalTo: view.centerYAnchor, constant: -250),
textFieldView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
textFieldView.bottomAnchor.constraint(equalTo: view.centerYAnchor, constant: -90),
textFieldView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 7/10),
textFieldLabel.topAnchor.constraint(equalTo: textFieldView.topAnchor),
textFieldLabel.centerXAnchor.constraint(equalTo: textFieldView.centerXAnchor),
textFieldLabel.widthAnchor.constraint(equalTo: textFieldView.widthAnchor),
textFieldLabel.heightAnchor.constraint(equalToConstant: 50),
textFieldField.centerXAnchor.constraint(equalTo: textFieldView.centerXAnchor),
textFieldField.centerYAnchor.constraint(equalTo: textFieldView.centerYAnchor, constant: -10),
textFieldField.heightAnchor.constraint(equalToConstant: 33),
textFieldField.widthAnchor.constraint(equalTo: textFieldView.widthAnchor, multiplier: 8.5/10),
textFieldButton.topAnchor.constraint(equalTo: textFieldField.bottomAnchor, constant: 15),
textFieldButton.bottomAnchor.constraint(equalTo: textFieldView.bottomAnchor),
textFieldButton.centerXAnchor.constraint(equalTo: textFieldView.centerXAnchor),
textFieldButton.widthAnchor.constraint(equalTo: textFieldView.widthAnchor),
])
}
#objc func textFieldButtonTap()
{
if textFieldField.text!.count < 1 || textFieldField.text == " " || textFieldField.text == " " || textFieldField.text == " "
{
let TooShort = UIAlertController(title: "TOO SHORT", message: "\n\nTHE NAME\n\n YOU ARE SAVING\n\nIS TOO SHORT\n", preferredStyle: .alert)
TooShort.view.tintColor = #colorLiteral(red: 0.5818830132, green: 0.2156915367, blue: 1, alpha: 1)
TooShort.view.layer.cornerRadius = 15
TooShort.view.layer.borderWidth = 5
TooShort.view.layer.borderColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1)
func okHandler(alert: UIAlertAction!)
{
// Do something if you feel like it
}
self.present(TooShort, animated: true, completion: nil)
TooShort.addAction(UIAlertAction(title: "OK", style: .default, handler: okHandler))
}
else
{
//DON'T DO WHAT I DO, DO SOMETHING EQUALLLY AWESOME
doingSomethingAwesome()
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500), execute:
{
self.textFieldField.text = .none
self.textFieldView.isHidden = true
})
}
}
func doingSomethingAwesome()
{
let saved = UIAlertController(title: "SAVED", message: "\n\nYOU HAVE\n\nSAVED THE NAME\n\n", preferredStyle: .alert)
saved.view.tintColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 1)
saved.view.layer.cornerRadius = 15
saved.view.layer.borderWidth = 5
saved.view.layer.borderColor = #colorLiteral(red: 0, green: 0.9768045545, blue: 0, alpha: 1)
func okHandler(alert: UIAlertAction!)
{
...
}
self.present(saved, animated: true, completion: nil)
saved.addAction(UIAlertAction(title: "OK", style: .default, handler: okHandler))
}
override func viewDidLoad() {
super.viewDidLoad()
createYourButton()
}
}
// Actually took me 30 mins to post this, so if I've missed something, let me know✌️
// Because I have a scrollView, I figured this was next best thing to disabling it while that view was showing
func scrollViewWillBeginDragging(_ scrollView: UIScrollView)
{
textFieldView.isHidden = true
}

Is it possible to customize UINavigationBar by protocol?

I want to customize UINavigationBar for some view controllers. For some reasons, I cannot just simply extend UIViewController. So I was trying to do it by a protocol.
What I have tried:
protocol TransparentNavigationBarProtocol {
func makeNavigationBarTransparent()
}
extension TransparentNavigationBarProtocol where Self: UIViewController {
func makeNavigationBarTransparent() {
if let navController = navigationController {
navController.navigationBar.setBackgroundImage(UIImage(), for: .default)
navController.navigationBar.shadowImage = UIImage()
navController.navigationBar.tintColor = UIColor.white
navController.navigationBar.barStyle = .blackTranslucent
navController.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
navController.navigationBar.backgroundColor = .clear
}
}
}
I added some breakpoints which show the function had been called successfully but the navigationBar didn't change. So I was wondering is it possible to achieve this by protocols?
For Xcode11, you need set a image, not nil
Also, in your viewcontroller's viewWillAppear, you need call makeNavigationBarTransparent()
func makeNavigationBarTransparent() {
if let navController = navigationController {
navController.navigationBar.setBackgroundImage(UIImage(), for: .default)
navController.navigationBar.shadowImage = UIImage()
navController.navigationBar.tintColor = UIColor.init(red: 74/255, green: 74/255, blue: 74/255, alpha: 1)
navController.navigationBar.barStyle = .default
navController.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(red: 74/255, green: 74/255, blue: 74/255, alpha: 1)]
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
makeNavigationBarTransparent()
}

How to customise UISearchController?

I'm using a UISearchController in my application but I can't figure a way to customise it. I looked here in Stackoverflow but none of the confirmed answers worked for me. I tried looking in more places but nothing works.
This is my code:
import UIKit
class MainVC: UIViewController {
lazy var mSearchBarController: UISearchController = {
let mSearchBar = UISearchController(searchResultsController: nil)
mSearchBar.searchBar.barStyle = .default
mSearchBar.searchBar.placeholder = "enter city here"
mSearchBar.searchBar.tintColor = UIColor.white
return mSearchBar
}()
override func viewDidLayoutSubviews() {
setupSearchBar()
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor(red: 80/255, green: 135/255, blue: 179/255, alpha: 1.0)
setupNavBar()
self.navigationItem.searchController = mSearchBarController
}
private func setupNavBar(){
navigationItem.title = "Home"
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.hidesSearchBarWhenScrolling = true
}
private func setupSearchBar(){
let mSearchTextField = mSearchBarController.searchBar.value(forKey: "searchField") as? UITextField
mSearchTextField?.textColor = UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)
let mAttributedPlaceholder = NSMutableAttributedString(string: "enter city here", attributes: [NSAttributedString.Key.foregroundColor : UIColor(red: 255/255, green: 245/255, blue: 139/255, alpha: 1.0)])
mSearchTextField?.attributedPlaceholder = mAttributedPlaceholder
for view in mSearchBarController.searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
}
I can't figure a way to change the textColor of the searchBar nor the backgroundColor of it.
This is what I get:
See I use this simple code to change the textColor and backgroundColor of seacrhBar:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
for view in searchBar.subviews {
for subview in view.subviews {
if let textField = subview as? UITextField {
textField.backgroundColor = UIColor.red
textField.textColor = UIColor.white
}
}
}
}
for reference you can check:-
How can I change the UISearchBar search text color? (for textcolor)
http://jitu1990.blogspot.com/2017/06/textcolor-and-backgroundcolor.html (for backgorund color)

How can I get a textview to trigger a scrollview to move up for the keyboard?

I'm creating a form that lives on a view within a scrollview. It contains two textFields and one textView. I've cobbled together some code from online resources(like this one) so that it scrolls up if a textField is ever too low on the view/obstructed by the keyboard. The problem is that it doesn't seem to work for textViews.
I've done my best to comprehend why textViews won't trigger the same behavior, but I could really use some help. Here's my VC code:
import UIKit
class AddAPlaceBasicInfoViewController: UIViewController, UITextFieldDelegate, UITextViewDelegate {
// Outlets
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var categoryTextField: UITextField!
#IBOutlet weak var descriptionTextView: UITextView!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(noti:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(noti:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
// Default to an disabled "Next" button.
nextButton.isEnabled = false
nextButton.backgroundColor = UIColor(red: 89/255, green: 89/255, blue: 89/255, alpha: 1/1)
// Check that fields are filled.
nameTextField.delegate = self
descriptionTextView.delegate = self
// Helper functions.
createToolbar()
descriptionTextViewSetup(descriptionTextView)
}
// Creates the done button above the category picker.
func createToolbar() {
// Creates an instance of UIToolbar() named "toolbar".
let toolbar = UIToolbar()
toolbar.sizeToFit()
// Set up button properties.
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(AddAPlaceBasicInfoViewController.dismissKeyboard))
// Set color to teal.
doneButton.tintColor = UIColor(red: 0/255, green: 134/255, blue: 111/255, alpha: 1)
// Set up button in the toolbar and make it interactive.
toolbar.setItems([doneButton], animated: false)
toolbar.isUserInteractionEnabled = true
// Add the toolbar as an accessory view to the category picker.
nameTextField.inputAccessoryView = toolbar
categoryTextField.inputAccessoryView = toolbar
descriptionTextView.inputAccessoryView = toolbar
// Set toolbar's background to white.
toolbar.backgroundColor = UIColor.white
}
// Function to dismiss the keyboard. Used when the user taps the "Done" button in the toolbar.
func dismissKeyboard() {
view.endEditing(true)
if nameTextField.text?.characters.count == 0 || categoryTextField.text?.characters.count == 0 || descriptionTextView.text == "What's this place like? (You'll be able to add a photo on the next screen)" {
nextButton.isEnabled = false
nextButton.backgroundColor = UIColor(red: 89/255, green: 89/255, blue: 89/255, alpha: 1/1)
} else {
nextButton.isEnabled = true
nextButton.backgroundColor = UIColor(red: 0/255, green: 134/255, blue: 111/255, alpha: 1/1)
}
}
// Function to create placeholder text.
func descriptionTextViewSetup(_ textView: UITextView) {
// Modifications
descriptionTextView.text = "What's this place like? (You'll be able to add a photo on the next screen)"
descriptionTextView.textColor = UIColor(red: 199/255, green: 199/255, blue: 205/255, alpha: 1/1)
descriptionTextView.textContainer.lineFragmentPadding = 0
//descriptionTextView.textColor = UIColor.lightGray
}
//---------------------------------
// MARK: - Notification Center
//---------------------------------
func keyboardWillHide(noti: Notification) {
let contentInsets = UIEdgeInsets.zero
scrollView.contentInset = contentInsets
scrollView.scrollIndicatorInsets = contentInsets
}
func keyboardWillShow(noti: Notification) {
guard let userInfo = noti.userInfo else { return }
guard var keyboardFrame: CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue else { return }
keyboardFrame = self.view.convert(keyboardFrame, from: nil)
var contentInset:UIEdgeInsets = scrollView.contentInset
contentInset.bottom = keyboardFrame.size.height
scrollView.contentInset = contentInset
}
}
If you are creating a Form for users where they can enter information then I would suggest using a static UITableView. Static UITableView can be used if your UIViewController is of type UITableViewController. Static TableView makes it very easy to place controls and since UITableView already has a UIScrollView it automatically scrolls when the UITextView is in focus.
Try it out:

How to prevent navbar hiding when keyboard appears ios?

I have an app which has a webview on a storyboard, which loads a registration form in ASP, so when the keyboard or a picker appears, the navbar hides, but never comes back, so I'm not able to go back to the last page.
Here's my code:
import UIKit
class BannerViewController: UIViewController {
#IBOutlet var webView11: UIWebView!
override var preferredStatusBarStyle: UIStatusBarStyle {
return .default
}
override var prefersStatusBarHidden: Bool {
return false
}
override func viewWillAppear(_ animated: Bool) {
self.navigationItem.setHidesBackButton(false, animated: true)
self.setNeedsStatusBarAppearanceUpdate()
self.navigationController?.navigationBar.barTintColor = UIColor(red: 0, green: 0.38, blue: 0.667, alpha: 1)
self.navigationController?.navigationBar.tintColor = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
var titleTextAttributes = [String : AnyObject]();
titleTextAttributes[NSFontAttributeName] = UIFont.systemFont(ofSize: 17, weight: UIFontWeightSemibold)
titleTextAttributes[NSForegroundColorAttributeName] = UIColor(red: 1, green: 1, blue: 1, alpha: 1)
self.navigationController?.navigationBar.titleTextAttributes = titleTextAttributes
}
override func viewDidLoad() {
super.viewDidLoad();
self.navigationController?.navigationBar.barStyle = .default
self.setNeedsStatusBarAppearanceUpdate()
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.webView11.delegate = self;
if let unwrappedwebView11 = URL(string: "http://www.stackoverflow") {
self.webView11.loadRequest(URLRequest(url: unwrappedwebView11))
}
}
}
extension BannerViewController: UIWebViewDelegate {
}
So, it looks like i need to refresh the view or something, as i added a back button out of the webView and when i click and go back to last view, and then i got in again to the webView the navBar doesn´t move anymore