I'm trying to set a tableView programmatically inside a viewController (before I worked in a TableViewController, so I kinda want to replace the tableViewController with a normal ViewController with a tableView inside)
But I always get nil error messages if I try following code:
class MessagesController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let cellId = "cellId"
private var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.setHidesBackButton(true, animated: false)
layoutFAB()
tableView = UITableView(frame:self.view.frame, style: .plain) // or any frame
tableView.delegate = self
tableView.dataSource = self
tableView.separatorColor = UIColor.black
tableView.tableFooterView = UIView()
tableView.backgroundColor = UIColor(red:0.36, green:0.39, blue:0.40, alpha:1.0)
navigationController?.navigationBar.tintColor = UIColor(red:1.00, green:0.96, blue:0.02, alpha:1.0)
let imageRight = UIImage(named: "new_message_icon")
navigationItem.rightBarButtonItem = UIBarButtonItem(image: imageRight, style: .plain, target: self, action: #selector(handleNewMessage))
tableView.register(UserCell.self, forCellReuseIdentifier: cellId)
tableView.allowsMultipleSelectionDuringEditing = true
self.view.addSubview(tableView)
}
func layoutFAB() {
let item = FloatyItem()
item.hasShadow = false
item.buttonColor = UIColor(red:1.00, green:0.96, blue:0.02, alpha:0.75) //yellow opcaity 0,75
item.circleShadowColor = UIColor.black
item.titleShadowColor = UIColor.black
item.titleLabelPosition = .right
item.handler = { item in
}
floaty.hasShadow = false
floaty.addItem (icon: UIImage(named: "most-537282")) { item in
self.navigationController?.popToRootViewController(animated: true)
self.navigationController?.navigationBar.isHidden = false
}
floaty.addItem (icon: UIImage(named: "add")) { item in
let addVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ComposeViewController") as! ComposeViewController
self.navigationController?.pushViewController(addVC, animated: true)
self.navigationController?.navigationBar.isHidden = false
}
floaty.addItem (icon: UIImage(named: "setting-512")) { item in
let settingsVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SettingsViewController") as! SettingsViewController
self.navigationController?.pushViewController(settingsVC, animated: true)
self.navigationController?.navigationBar.isHidden = false
}
floaty.paddingX = self.view.frame.width/2 - floaty.frame.width/2
floaty.fabDelegate = self
self.view.addSubview(floaty)
}
You miss
tableView = UITableView(frame:self.view.frame) // or any frame
tableView.delegate = self
tableView.dataSource = self
If you want to set style.grouped use this initailizer
tableView = UITableView(frame:self.view.frame,style:.grouped) // or any frame
Related
I have been at this for some time now. I can not get my tableView to appear. I think it has something to do with the fact that it is being presented as didMove(toParent)
I am trying to create a page that allows you to add a new Card to the profile. Every time I write it programmatically or use storyboard it crashes as it Unexpectedly found nil while implicitly unwrapping an Optional value.
Here is the view Controller that is presenting the Side Menu
import Foundation
import SideMenu
import FirebaseAuth
import UIKit
import CoreLocation
import SwiftUI
class BeginViewController: UIViewController, MenuControllerDelegate, CLLocationManagerDelegate {
private var sideMenu: SideMenuNavigationController?
struct customData {
var title: String
var image: UIImage
}
let data = [
customData(title: "NottingHill", image: #imageLiteral(resourceName: "norali-nayla-SAhImiWmFaw-unsplash")),
customData(title: "Southall", image: #imageLiteral(resourceName: "alistair-macrobert-8wMflrTLm2g-unsplash")),
customData(title: "Tower Hill", image: #imageLiteral(resourceName: "peregrine-communications-0OLnnZWg860-unsplash")),
customData(title: "Mansion House", image: #imageLiteral(resourceName: "adam-birkett-cndNklOnHO4-unsplash")),
customData(title: "Westminster", image: #imageLiteral(resourceName: "simon-mumenthaler-NykjYbCW6Z0-unsplash")),
customData(title: "London Bridge", image: #imageLiteral(resourceName: "hert-niks-CjouXgWrTRk-unsplash"))
]
struct Constants {
static let cornerRadius: CGFloat = 15.0 }
let manager = CLLocationManager()
private let ProfileController = ProfileViewController()
private let MyBookingsController = MyBookingsViewController()
private let WalletController = WalletViewController()
private let FAQController = FAQViewController()
private let SettingsController = SettingsViewController()
#IBOutlet weak var StoreButton: UIButton!
#IBOutlet weak var DeliverButton: UIButton!
#IBOutlet weak var AirportButton: UIButton!
#IBOutlet weak var HotelsButton: UIButton!
fileprivate let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.translatesAutoresizingMaskIntoConstraints = false
cv.register(customCell.self, forCellWithReuseIdentifier: "cell")
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
// buttons
StoreButton.layer.cornerRadius = Constants.cornerRadius
StoreButton.layer.shadowOffset = .zero
StoreButton.layer.shadowOpacity = 0.3
StoreButton.layer.shadowColor = UIColor.black.cgColor
StoreButton.layer.shadowRadius = 5
DeliverButton.layer.cornerRadius = Constants.cornerRadius
DeliverButton.layer.shadowOffset = .zero
DeliverButton.layer.shadowOpacity = 0.3
DeliverButton.layer.shadowColor = UIColor.black.cgColor
DeliverButton.layer.shadowRadius = 5
AirportButton.layer.cornerRadius = Constants.cornerRadius
AirportButton.layer.shadowOffset = .zero
AirportButton.layer.shadowOpacity = 0.3
AirportButton.layer.shadowColor = UIColor.black.cgColor
AirportButton.layer.shadowRadius = 5
HotelsButton.layer.cornerRadius = Constants.cornerRadius
HotelsButton.layer.shadowOffset = .zero
HotelsButton.layer.shadowOpacity = 0.3
HotelsButton.layer.shadowColor = UIColor.black.cgColor
HotelsButton.layer.shadowRadius = 5
//CollectionViewNearbyPlaces
view.addSubview(collectionView)
collectionView.backgroundColor = .clear
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 450).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 25).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
collectionView.heightAnchor.constraint(equalTo: collectionView.widthAnchor, multiplier: 0.5).isActive = true
collectionView.delegate = self
collectionView.dataSource = self
// title
title = "handl"
//background
let menu = MenuController(with: [ "Home", "Profile", "My Bookings",
"Wallet",
"FAQ","Settings"])
menu.delegate = self
sideMenu = SideMenuNavigationController(rootViewController: menu)
sideMenu?.leftSide = true
sideMenu?.setNavigationBarHidden(true, animated: false)
SideMenuManager.default.leftMenuNavigationController = sideMenu
SideMenuManager.default.addPanGestureToPresent(toView: view)
addChildControllers()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
handleNotAuthenticated()
}
private func addChildControllers() {
addChild(ProfileController)
addChild(MyBookingsController)
addChild(WalletController)
addChild(FAQController)
addChild(SettingsController)
view.addSubview(ProfileController.view)
view.addSubview(MyBookingsController.view)
view.addSubview(WalletController.view)
view.addSubview(FAQController.view)
view.addSubview(SettingsController.view)
ProfileController.view.frame = view.bounds
MyBookingsController.view.frame = view.bounds
WalletController.view.frame = view.bounds
FAQController.view.frame = view.bounds
SettingsController.view.frame = view.bounds
ProfileController.didMove(toParent: self)
MyBookingsController.didMove(toParent: self)
WalletController.didMove(toParent: self)
FAQController.didMove(toParent: self)
SettingsController.didMove(toParent: self)
ProfileController.view.isHidden = true
MyBookingsController.view.isHidden = true
WalletController.view.isHidden = true
FAQController.view.isHidden = true
SettingsController.view.isHidden = true
}
#IBAction func SideMenuButton(_ sender: Any) {
present(sideMenu!, animated: true)
}
func didSelectMenuItem(named: String) {
sideMenu?.dismiss(animated: true, completion: { [weak self] in
self?.title = named
if named == "Home" {
self?.ProfileController.view.isHidden = true
self?.MyBookingsController.view.isHidden = true
self?.WalletController.view.isHidden = true
self?.FAQController.view.isHidden = true
self?.SettingsController.view.isHidden = true
}
if named == "Profile" {
self?.ProfileController.view.isHidden = false
self?.MyBookingsController.view.isHidden = true
self?.WalletController.view.isHidden = true
self?.FAQController.view.isHidden = true
self?.SettingsController.view.isHidden = true
}
if named == "My Bookings" {
self?.ProfileController.view.isHidden = true
self?.MyBookingsController.view.isHidden = false
self?.WalletController.view.isHidden = true
self?.FAQController.view.isHidden = true
self?.SettingsController.view.isHidden = true
}
else if named == "Wallet" {
self?.ProfileController.view.isHidden = true
self?.MyBookingsController.view.isHidden = true
self?.WalletController.view.isHidden = false
self?.FAQController.view.isHidden = true
self?.SettingsController.view.isHidden = true
}
else if named == "FAQ" {
self?.ProfileController.view.isHidden = true
self?.MyBookingsController.view.isHidden = true
self?.WalletController.view.isHidden = true
self?.FAQController.view.isHidden = false
self?.SettingsController.view.isHidden = true
}
else if named == "Settings" {
self?.ProfileController.view.isHidden = true
self?.MyBookingsController.view.isHidden = true
self?.WalletController.view.isHidden = true
self?.FAQController.view.isHidden = true
self?.SettingsController.view.isHidden = false
}
})
}
}
extension BeginViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width/2.5, height: collectionView.frame.width/2)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! customCell
cell.data = self.data[indexPath.row]
return cell
}
class customCell: UICollectionViewCell {
var data: customData? {
didSet {
guard let data = data else { return }
bg.image = data.image
}
}
fileprivate let bg: UIImageView = {
let iv = UIImageView()
iv.image = #imageLiteral(resourceName: "adam-birkett-cndNklOnHO4-unsplash")
iv.translatesAutoresizingMaskIntoConstraints = false
iv.contentMode = .scaleAspectFill
iv.layer.shadowColor = UIColor.black.cgColor
iv.layer.shadowOpacity = 1
iv.layer.shadowOffset = CGSize.zero
iv.layer.shadowRadius = 10
iv.layer.shadowPath = UIBezierPath(rect: iv.bounds).cgPath
iv.layer.shouldRasterize = false
iv.layer.cornerRadius = 10
iv.clipsToBounds = true
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(bg)
bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//if user is not logged in show login
private func handleNotAuthenticated() {
//check auth status
if Auth.auth().currentUser == nil {
//show log in screen
let loginVC = LoginViewController()
loginVC.modalPresentationStyle = .fullScreen
present(loginVC, animated: false)
}
}
}
and Here is the viewController I am trying to present a tableView on. It comes up with a white screen, but no tableView. Nor are my navigation items showing. Even when written programmatically.
import UIKit
class WalletViewController: UIViewController {
var addNewCard = [String]()
let button = UIButton()
let tableView = UITableView()
// MARK: - Properties
override func viewDidLoad() {
super.viewDidLoad()
addTable()
view.backgroundColor = UIColor(named: "RED")
button.setTitle("Add New Card", for: .normal)
view.addSubview(button)
button.backgroundColor = UIColor(named: "yellow-2")
button.setTitleColor(UIColor(named: "RED"), for: .normal)
button.frame = CGRect(x: 25, y: 700, width: 350, height: 50)
button.layer.cornerRadius = 15
button.addTarget(self, action: #selector(didTapAddButton), for: .touchUpInside)
if !UserDefaults().bool(forKey: "setup") {
UserDefaults().set(true, forKey: "setup")
UserDefaults().set(0, forKey: "count")
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add New Card", style: .plain, target: self,
action: #selector(didTapAdd))
}
}
func updateCard() {
guard let count = UserDefaults().value(forKey: "count") as? Int else {
return
}
for x in 0..<count {
if let addCard = UserDefaults().value(forKey: "addCard\(x+1)") as? String {
addNewCard.append(addCard)
}
}
}
func addTable() {
tableView.frame = view.bounds
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .singleLine
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "addCard")
self.view.addSubview(tableView)
}
#IBAction func didTapAdd() {
let vc = storyboard?.instantiateViewController(withIdentifier: "addCard") as! addCardViewController
vc.update = {
DispatchQueue.main.async {
self.updateCard()
}
}
navigationController?.pushViewController(vc, animated: true)
}
#objc private func didTapAddButton() {
let rootVC = addCardViewController()
let navVC = UINavigationController(rootViewController: rootVC)
navVC.modalPresentationStyle = .fullScreen
present(navVC, animated: true)
}
}
extension WalletViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
extension WalletViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let add = tableView.dequeueReusableCell(withIdentifier: "addCard", for: indexPath)
add.textLabel?.text = addNewCard[indexPath.row]
return add
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return addNewCard.count
}
}
If i test the app on large screen simulator everything works well, but the moment i test the code in small screen simulator, there is no error but the cells that are not visible and can be seen only while scrolling gets attached to top of screen, strangely enough if i scroll down again i can see the labels and text fields looking like they are moving from top to their original locations, but they do not and remain on screen top, i am posting the image , where could i be making the mistake below is code of file and image , the misbehaviour happens when i scroll
import UIKit
import CoreData
class RestaurantAddController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate, UITextViewDelegate, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
let displayInputForm = UITableView()
var restaurant: Restaurant!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 6
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = displayInputForm.dequeueReusableCell(withIdentifier: String(describing: RestaurantAddViewCells.self), for: indexPath) as! RestaurantAddViewCells
cell.heightAnchor.constraint(greaterThanOrEqualToConstant: 100).isActive = true
view.addSubview(cell)
// view.addSubview(cell.contentView)
view.addSubview(cell.imageToUpload)
view.addSubview(cell.nameToUploadLabel)
view.addSubview(cell.nameToUploadTextField)
view.addSubview(cell.typeToUploadLabel)
view.addSubview(cell.typeToUploadTextField)
view.addSubview(cell.locationToUploadLabel)
view.addSubview(cell.locationToUploadTextField)
view.addSubview(cell.phoneToUploadLabel)
view.addSubview(cell.phoneToUPloadTextField)
view.addSubview(cell.summartyToUploadLabel)
view.addSubview(cell.summaryToUploadTextView)
//Add to cell via stackView
let stackEntry = UIStackView()
view.addSubview(stackEntry)
stackEntry.translatesAutoresizingMaskIntoConstraints = false
stackEntry.alignment = .top
stackEntry.axis = .vertical
stackEntry.spacing = 5.0
stackEntry.distribution = .fill
stackEntry.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 10).isActive = true
stackEntry.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
stackEntry.topAnchor.constraint(equalTo: cell.topAnchor, constant: 20).isActive = true
//add scroll view
// let scrollView = UIScrollView()
// view.addSubview(scrollView)
// scrollView.translatesAutoresizingMaskIntoConstraints = false
// scrollView.topAnchor.constraint(equalTo: displayInputForm.topAnchor).isActive = true
// scrollView.bottomAnchor.constraint(equalTo: displayInputForm.bottomAnchor).isActive = true
// scrollView.leadingAnchor.constraint(equalTo: displayInputForm.leadingAnchor).isActive = true
// scrollView.trailingAnchor.constraint(equalTo: displayInputForm.trailingAnchor).isActive = true
// scrollView.addSubview(stackEntry)
//MARK:- give custom font
let font = UIFont(name: "Rubik-Medium", size: 18)
let fontMetrics = UIFontMetrics(forTextStyle: .body)
let labels = [cell.locationToUploadLabel, cell.typeToUploadLabel, cell.nameToUploadLabel, cell.phoneToUploadLabel, cell.summartyToUploadLabel]
labels.forEach { label in
label.font = fontMetrics.scaledFont(for: font!)
}
let textCusotm = [cell.nameToUploadTextField, cell.typeToUploadTextField, cell.locationToUploadTextField, cell.phoneToUPloadTextField]
textCusotm.forEach { (fields) in
fields.font = fontMetrics.scaledFont(for: font!)
}
cell.summaryToUploadTextView.font = fontMetrics.scaledFont(for: font!)
//MARK:- add cell per row
switch indexPath.row {
case 0:
cell.heightAnchor.constraint(greaterThanOrEqualToConstant: 250).isActive = true
let buttonImage = UIImageView()
cell.backgroundColor = UIColor.lightGray
buttonImage.translatesAutoresizingMaskIntoConstraints = false
buttonImage.image = UIImage(named: "photo")
view.addSubview(buttonImage)
buttonImage.heightAnchor.constraint(equalToConstant: 30).isActive = true
buttonImage.widthAnchor.constraint(equalToConstant: 30).isActive = true
buttonImage.centerXAnchor.constraint(equalTo: cell.centerXAnchor).isActive = true
buttonImage.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
return cell
case 1:
cell.selectionStyle = .none
cell.nameToUploadLabel.text = "Name of Hotel:"
cell.nameToUploadTextField.placeholder = "Enter Hotel Name"
cell.nameToUploadTextField.tag = 1
cell.nameToUploadTextField.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
stackEntry.addArrangedSubview(cell.nameToUploadLabel)
stackEntry.addArrangedSubview(cell.nameToUploadTextField)
// cell.nameToUploadTextField.becomeFirstResponder()
cell.nameToUploadTextField.delegate = self
return cell
case 2:
cell.selectionStyle = .none
cell.typeToUploadLabel.text = "Type Of Hotel:"
cell.typeToUploadTextField.placeholder = "Name type of hotel"
cell.typeToUploadTextField.tag = 2
cell.typeToUploadTextField.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
stackEntry.addArrangedSubview(cell.typeToUploadLabel)
stackEntry.addArrangedSubview(cell.typeToUploadTextField)
cell.typeToUploadTextField.delegate = self
return cell
case 3:
cell.selectionStyle = .none
cell.locationToUploadLabel.text = "Location of Hotel:"
cell.locationToUploadTextField.placeholder = "Enter Hotel Location"
cell.locationToUploadTextField.tag = 3
cell.locationToUploadTextField.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
stackEntry.addArrangedSubview(cell.locationToUploadLabel)
stackEntry.addArrangedSubview(cell.locationToUploadTextField)
cell.locationToUploadTextField.delegate = self
return cell
case 4:
cell.selectionStyle = .none
cell.phoneToUploadLabel.text = "Phone:"
cell.phoneToUPloadTextField.placeholder = "Enter Phone"
cell.phoneToUPloadTextField.tag = 4
cell.phoneToUPloadTextField.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
stackEntry.addArrangedSubview(cell.phoneToUploadLabel)
stackEntry.addArrangedSubview(cell.phoneToUPloadTextField)
cell.phoneToUPloadTextField.delegate = self
return cell
case 5:
cell.selectionStyle = .none
cell.summartyToUploadLabel.text = "Enter Summary:"
//cell.summaryToUploadTextView.place
cell.summaryToUploadTextView.tag = 5
cell.summaryToUploadTextView.heightAnchor.constraint(equalToConstant: 200).isActive = true
cell.summaryToUploadTextView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - 20).isActive = true
cell.summaryToUploadTextView.layer.borderWidth = 1
cell.summaryToUploadTextView.layer.cornerRadius = 5.0
cell.summaryToUploadTextView.layer.borderColor = UIColor.lightGray.cgColor
stackEntry.addArrangedSubview(cell.summartyToUploadLabel)
stackEntry.addArrangedSubview(cell.summaryToUploadTextView)
cell.summaryToUploadTextView.delegate = self
return cell
default:
fatalError("No data found")
}
}
override func viewDidLoad() {
super.viewDidLoad()
displayInputForm.delegate = self
displayInputForm.dataSource = self
//MARK:- Add scroll view
view.addSubview(displayInputForm)
let footerView = UIView()
displayInputForm.tableFooterView = footerView
// Do any additional setup after loading the view.
//Add pinning of table
displayInputForm.translatesAutoresizingMaskIntoConstraints = false
self.displayInputForm.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
self.displayInputForm.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
self.displayInputForm.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
self.displayInputForm.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
//Change the back button to arrow
let imgBack = UIImage(named: "back")
navigationController?.navigationBar.backIndicatorImage = imgBack
navigationController?.navigationBar.backIndicatorTransitionMaskImage = imgBack
navigationItem.leftItemsSupplementBackButton = true
navigationController?.navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: nil)
// Register a cell
displayInputForm.register(RestaurantAddViewCells.self, forCellReuseIdentifier: String(describing: RestaurantAddViewCells.self))
//MARK:- add the cancel and save button
self.navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "close"), style: .done, target: self, action: #selector(closeRestaurant))
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: UIImage(named: "save"), style: .plain, target: self, action: #selector(saveRestaurantData))
}
//MARK:- close function
#objc func closeRestaurant() {
self.navigationController?.popViewController(animated: true)
}
//MARK:- save function
#objc func saveRestaurantData() {
let indexPath0 = IndexPath(row: 1, section: 0)
let cell0 = displayInputForm.cellForRow(at: indexPath0) as! RestaurantAddViewCells
let nameVal = cell0.nameToUploadTextField.text
let indexPath1 = IndexPath(row: 2, section: 0)
let cell1 = displayInputForm.cellForRow(at: indexPath1) as! RestaurantAddViewCells
let typeVal = cell1.typeToUploadTextField.text
let indexPath2 = IndexPath(row: 3, section: 0)
let cell2 = displayInputForm.cellForRow(at: indexPath2) as! RestaurantAddViewCells
let locationVal = cell2.locationToUploadTextField.text
let indexPath3 = IndexPath(row: 4, section: 0)
let cell3 = displayInputForm.cellForRow(at: indexPath3) as! RestaurantAddViewCells
let phoneVal = cell3.phoneToUPloadTextField.text
let indexPath4 = IndexPath(row: 5, section: 0)
let cell4 = displayInputForm.cellForRow(at: indexPath4) as! RestaurantAddViewCells
let summaryVal = cell4.summaryToUploadTextView.text
let indexPath5 = IndexPath(row: 0, section: 0)
let cell5 = displayInputForm.cellForRow(at: indexPath5) as! RestaurantAddViewCells
let imageVal = cell5.imageToUpload.image
if (imageVal == nil || nameVal == "" || typeVal == "" || locationVal == "" || phoneVal == "" || summaryVal == "") {
let saveAlertController = UIAlertController(title: "Empty Fields", message: "Fill all the fileds", preferredStyle: .alert)
let saveAlertAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
saveAlertController.addAction(saveAlertAction)
self.present(saveAlertController, animated: true) {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dissMissAlertController))
saveAlertController.view.superview?.subviews[0].addGestureRecognizer(tapGesture)
}
}
else {
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
let context = appDelegate.persistentContainer.viewContext
restaurant = Restaurant(context: context)
restaurant.name = nameVal
restaurant.type = typeVal
restaurant.location = locationVal
restaurant.phone = phoneVal
restaurant.summary = summaryVal
if let restaurantImage = cell5.imageToUpload.image {
restaurant.image = restaurantImage.pngData()
}
print("data saved")
appDelegate.saveContext()
}
}
self.navigationController?.popViewController(animated: false)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
override func viewWillAppear(_ animated: Bool) {
self.title = "Add Restaurants"
}
//MARK:- check if textfield can be moved to next one on return key press
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let nextField = view.viewWithTag(textField.tag + 1) as? UITextField {
textField.resignFirstResponder()
nextField.becomeFirstResponder()
// nextField.endEditing(false)
}
return true
}
//MARK:- add sction to row clicks
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0 {
let UIImageAlertController = UIAlertController(title: "", message: "Select an option", preferredStyle: .actionSheet)
let photoGalleryAction = UIAlertAction(title: "PhotoLibrary", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imageController = UIImagePickerController()
imageController.allowsEditing = false
imageController.sourceType = .photoLibrary
imageController.delegate = self
self.present(imageController, animated: true, completion: nil)
}
}
UIImageAlertController.addAction(photoGalleryAction)
let cameraPicturesAction = UIAlertAction(title: "Camera", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let cameraController = UIImagePickerController()
cameraController.allowsEditing = false
cameraController.sourceType = .camera
cameraController.delegate = self
self.present(cameraController, animated: true, completion: nil)
}
}
UIImageAlertController.addAction(cameraPicturesAction)
self.present(UIImageAlertController, animated: true) {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.dissMissAlertController))
UIImageAlertController.view.superview?.subviews[0].addGestureRecognizer(tapGesture)
}
}
}
#objc func dissMissAlertController() {
self.dismiss(animated: true, completion: nil)
}
//MARK:- function to add and select a picture and then add it
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let selectedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
if let indexPath = displayInputForm.indexPathForSelectedRow {
let cell = displayInputForm.cellForRow(at: indexPath) as! RestaurantAddViewCells
cell.imageToUpload.translatesAutoresizingMaskIntoConstraints = false
cell.imageToUpload.widthAnchor.constraint(equalTo: cell.widthAnchor).isActive = true
cell.imageToUpload.heightAnchor.constraint(equalToConstant: 250).isActive = true
cell.imageToUpload.topAnchor.constraint(equalTo: cell.topAnchor).isActive = true
cell.imageToUpload.image = selectedImage
cell.contentMode = .scaleAspectFill
cell.clipsToBounds = true
}
dismiss(animated: true, completion: nil)
}
}
}
Solution
add this line in viewdidload, where the tableName is the instance of your table
<tableName>.contentInsetAdjustmentBehavior = .never
I have a main view controller, it has a fullscreen UITableView which is populated by values from Firebase and a TabBarController below. All the code for the UITableView is handled programmatically. I need to add two options: Firstly, a search bar to query the results and a filter option for the various categories to fetch from Firebase.
Here is my updated code from the ViewController:
import UIKit
import Firebase
class PostTable: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchControllerDelegate,UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
}
var tableView:UITableView!
var posts = [Post]()
var searchController : UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
if Auth.auth().currentUser == nil {
switchStoryboard()
}
tableView = UITableView(frame: view.bounds, style: .plain)
view.addSubview(tableView)
let cellNib = UINib(nibName: "PostTableViewCell", bundle: nil)
tableView.register(cellNib, forCellReuseIdentifier: "postCell")
var layoutGuide:UILayoutGuide!
layoutGuide = view.safeAreaLayoutGuide
tableView.leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: layoutGuide.topAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).isActive = true
tableView.delegate = self
tableView.dataSource = self
tableView.tableFooterView = UIView()
tableView.reloadData()
searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false // displays tableview
let scb = self.searchController.searchBar
scb.tintColor = UIColor.white
scb.placeholder = "SEARCH"
scb.barTintColor = UIColor.white
if let textfield = scb.value(forKey: "searchField") as? UITextField {
textfield.textColor = UIColor.green
if let backgroundview = textfield.subviews.first {
backgroundview.backgroundColor = UIColor.white
backgroundview.layer.cornerRadius = 10
backgroundview.clipsToBounds = true
}
}
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
} else {
self.tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.tintColor = UIColor.green
searchController.searchBar.barTintColor = UIColor.green
}
definesPresentationContext = true
observePosts()
}
Add variable of UISearchController
var searchController : UISearchController!
& then add code in viewDidLoad
searchController = UISearchController(searchResultsController: nil)
searchController.delegate = self
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false // displays tableview
let scb = self.searchController.searchBar
scb.tintColor = UIColor.white
scb.placeholder = "SEARCH"
scb.barTintColor = UIColor.white
if let textfield = scb.value(forKey: "searchField") as? UITextField {
textfield.textColor = UIColor.greenColor
if let backgroundview = textfield.subviews.first {
backgroundview.backgroundColor = UIColor.white
backgroundview.layer.cornerRadius = 10
backgroundview.clipsToBounds = true
}
}
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
} else {
self.tableView.tableHeaderView = searchController.searchBar
searchController.searchBar.tintColor = UIColor.greenColor
searchController.searchBar.barTintColor = UIColor.greenColor
}
definesPresentationContext = true
An UITabbarController does not have a UINavigationController so it doesn't have a UINavigationBar.
So you could do:
Add a cell to your TableView to act like a search bar
Add a Navigationbar to the ViewController
Add a custom View to your View to act as a container
There may be more options, just want to point you into the right direction.
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.autocapitalizationType = .none
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
// Make the search bar always visible.
navigationItem.hidesSearchBarWhenScrolling = false
} else {
// For iOS 10 and earlier, place the search controller's search bar in the table view's header.
tableView.tableHeaderView = searchController.searchBar
}
searchController.delegate = self
searchController.dimsBackgroundDuringPresentation = false // The default is true.
}
The search bar on iOS 9.3 keeps hiding behind table view although it is part of its header. How can I make it consistent between iOS versions?
One such difference:
on iOS 11
on iOS 9.3
in SelectCountryViewController: UITableViewController, UISearchBarDelegate, UISearchResultsUpdating:
self.tableView.delegate = self;
configureSearchController()
self.automaticallyAdjustsScrollViewInsets = false;
definesPresentationContext = true
let searchButton: UIBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(searchButtonAction))
searchButton.image = UIImage(named: "search")
self.navigationItem.rightBarButtonItem = searchButton
refreshController.attributedTitle = NSAttributedString(string: "")
refreshController.addTarget(self, action: #selector(refreshSelector), for: .valueChanged)
tableView.addSubview(refreshController)
func configureSearchController()
{
resultsController.tableView.delegate = self
resultsController.tableView.dataSource = self
self.searchController = UISearchController(searchResultsController: self.resultsController)
//self.tableView.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
self.searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.delegate = self
self.searchController.searchBar.scopeButtonTitles = []
for subView in searchController.searchBar.subviews {
for subViewOne in subView.subviews {
if subViewOne is UITextField {
searchTextField = subViewOne as! UITextField
subViewOne.backgroundColor = UIColor.white
break
}
}
}
self.automaticallyAdjustsScrollViewInsets = false;
extendedLayoutIncludesOpaqueBars = true
definesPresentationContext = true
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
// tableView.setContentOffset(self.navigationItem, animated: true)
searchController.searchBar.barTintColor = UIColor.white
//searchController.searchBar.layer.borderColor = UIColor.white.cgColor
searchTextField.backgroundColor = UIColor.searchBarTextFieldGrey()
return true
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
self.searchController.searchBar.showsCancelButton = false
// searchController.searchBar.barTintColor = nil
searchTextField.backgroundColor = UIColor.white
searchController.searchBar.barTintColor = nil
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.navigationBar.shadowImage = nil
}
#objc func refreshSelector()
{
if(!searchLoaded)
{
searchLoaded = true
self.tableView.tableHeaderView = searchController.searchBar
print( "Got ya")
self.navigationItem.rightBarButtonItem = nil
}
refreshController.endRefreshing()
}
#objc func searchButtonAction() {
if(!searchLoaded)
{
searchLoaded = true
self.tableView.tableHeaderView = searchController.searchBar
// self.navigationItem.titleView = searchController.searchBar
}
self.searchController.searchBar.becomeFirstResponder()
self.searchController.searchBar.text = ""
self.navigationItem.rightBarButtonItem = nil
}
I have a viewcontroller that allows users to create accounts. Once the account is created, I am trying to instantiate a new viewcontroller called intermediate vc programmatically. I have searched through stack overflow and I can't seem to find any relevant answers. I'm not able to set an identifier for the viewcontroller since it's not part of storyboard.
I created a button in my createAccountController that should result in the transition to the next screen.
here is the relevant code for my createAccountController
let testButton: UIButton = UIButton()
override func viewDidLoad() {
view.addSubview(testButton)
testButton.backgroundColor = UIColor.black
testButton.setTitle("Hi", for: .normal)
testButton.translatesAutoresizingMaskIntoConstraints = false
testButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
testButton.centerYAnchor.constraint(equalTo: usernameName.centerYAnchor, constant: 20).isActive = true
testButton.addTarget(self, action: #selector(moveToIntermediate), for: .touchUpInside)
}
intermediateViewController is the viewcontroller class I created within my createAccountController, and then function below is the function in my createAccountController.
#objc func moveToIntermediate() {
let interMediate = intermediateViewController()
interMediate.modalTransitionStyle = .crossDissolve
interMediate.view.layer.speed = 0.2
self.present(interMediate, animated: true, completion: nil)
}
Here is the intermediateViewController code
class intermediateViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let floatingButton: UIButton = UIButton()
let categoryTableView: UITableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
setTableView()
setNavBar()
setFloatingButton()
//when view starts
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
//you can dispose of stuff here
}
func setTableView() {
categoryTableView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(categoryTableView)
categoryTableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
categoryTableView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
categoryTableView.topAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true
categoryTableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = categoryTableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
return cell
}
func setNavBar() {
self.navigationController?.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(moveToNext))
self.navigationController?.navigationBar.backgroundColor = UIColor(red:0.22, green:0.46, blue:0.82, alpha:1.0)
self.navigationController?.navigationBar.topItem?.title = "Categories"
self.title = "some title"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.black]
self.navigationController?.navigationBar.isTranslucent = false
//self.transitioningDelegate
//self.translatesAutoresizingMaskIntoConstraints = false
}
#IBAction func moveToNext() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let moveToTabBar = storyboard.instantiateViewController(withIdentifier: "TabBarViewController")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = moveToTabBar
}
func setFloatingButton() {
floatingButton.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(floatingButton)
floatingButton.frame.size = CGSize(width: 150, height: 50)
floatingButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
floatingButton.centerYAnchor.constraint(equalTo: self.view.bottomAnchor, constant: floatingButton.frame.size.height).isActive = true
floatingButton.layer.cornerRadius = floatingButton.frame.size.height/2
floatingButton.backgroundColor = UIColor.black
floatingButton.setTitle("Done", for: .normal)
floatingButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
floatingButton.setTitleColor(UIColor.white, for: .normal)
}
}
In your constraints:
categoryTableView.topAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0.0).isActive = true
categoryTableView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
top and bottom anchors equal self.view.bottomAnchor
Update: just saw that Axazeano had already found the answer.
You made a small typo in a constraint:
categoryTableView.topAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
Corrected version:
categoryTableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
Also: do not forget to set the viewController as the dataSource of your tableView.