Presenting view controller without identifier programmatically results in black screen - ios

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.

Related

Passing Data from one ViewController to Another Programmatically, Swift [duplicate]

This question already has answers here:
How to pass data from modal view controller back when dismissed
(4 answers)
Closed 2 years ago.
I just want to transfer some data between two ViewControllers and also wrote some Code. But, if I update my tableView, the user-given data isn't presented at the tableView. Can anyone help me?
import UIKit
import CoreData
class AddNewRecipeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
private let reuseIdentifer = "IngredientCell"
let pressGesture = UILongPressGestureRecognizer()
let titleLabel = UILabel()
let tf_one = UITextField()
let tf_two = UITextField()
let tableView = UITableView()
let submitButton = UIButton()
let newButton = UIButton()
var name_array = [String]()
var unit_array = [String]()
var quantity_array = [String]()
let recipeId = Int.random(in: 0...5000)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
createViewControllerItems()
}
#objc func refresh(){
print(name_array)
self.tableView.reloadData()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
func createViewControllerItems() {
// - MARK: Titel
titleLabel.text = "Neues Rezept"
titleLabel.textColor = .black
titleLabel.textAlignment = .center
titleLabel.font = UIFont(name: "Bradley Hand", size: 24)
view.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
titleLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
titleLabel.widthAnchor.constraint(equalToConstant: 200).isActive = true
titleLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true
newButton.setTitle("test", for: UIControl.State.normal)
newButton.setTitleColor(.black, for: UIControl.State.normal)
newButton.addTarget(self, action: #selector(refresh), for: .touchUpInside)
view.addSubview(newButton)
newButton.translatesAutoresizingMaskIntoConstraints = false
newButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30).isActive = true
newButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
newButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
newButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
// - MARK: Überschrift
tf_one.placeholder = "Name"
tf_one.borderStyle = .roundedRect
tf_one.keyboardType = .default
tf_one.spellCheckingType = .yes
tf_one.smartInsertDeleteType = .yes
tf_one.autocorrectionType = .yes
tf_one.autocapitalizationType = .sentences
view.addSubview(tf_one)
tf_one.translatesAutoresizingMaskIntoConstraints = false
tf_one.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 15).isActive = true
tf_one.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
tf_one.widthAnchor.constraint(equalToConstant: 270).isActive = true
tf_one.heightAnchor.constraint(equalToConstant: 34).isActive = true
// - MARK: Anzahl Portionen
tf_two.placeholder = "Anzahl"
tf_two.borderStyle = .roundedRect
tf_two.keyboardType = .decimalPad
view.addSubview(tf_two)
tf_two.translatesAutoresizingMaskIntoConstraints = false
tf_two.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
tf_two.leftAnchor.constraint(equalTo: tf_one.rightAnchor, constant: 3).isActive = true
tf_two.widthAnchor.constraint(equalToConstant: 70).isActive = true
tf_two.heightAnchor.constraint(equalToConstant: 34).isActive = true
// - MARK: Table View
tableView.delegate = self
tableView.dataSource = self
tableView.register(IngredientCell.self, forCellReuseIdentifier: reuseIdentifer)
tableView.rowHeight = 55
view.addSubview(tableView)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100).isActive = true
tableView.topAnchor.constraint(equalTo: tf_one.bottomAnchor, constant: 10).isActive = true
// - MARK: Bestätigen
submitButton.layer.cornerRadius = 20
submitButton.clipsToBounds = true
submitButton.backgroundColor = .lightGray
submitButton.setTitle("ok", for: UIControl.State.normal)
submitButton.setTitleColor(.white, for: UIControl.State.normal)
submitButton.titleLabel?.font = UIFont(name: "Chalkduster", size: 24)
submitButton.addTarget(self, action: #selector(save), for: .touchUpInside)
view.addSubview(submitButton)
submitButton.translatesAutoresizingMaskIntoConstraints = false
submitButton.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -30).isActive = true
submitButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 30).isActive = true
submitButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
submitButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
// - MARK: Add Gesture
pressGesture.addTarget(self, action: #selector(pressAction))
view.addGestureRecognizer(pressGesture)
}
#objc func pressAction() {
let generator = UIImpactFeedbackGenerator(style: .heavy)
generator.impactOccurred()
let vc: AddNewIngredientViewController!
vc = AddNewIngredientViewController()
vc.modalPresentationStyle = .automatic
self.present(vc, animated: true)
}
#objc func save() {
//save befor dismiss
dismiss(animated: true, completion: nil)
/*
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let context = appDelegate.persistentContainer.viewContext
let entityName = "Recipes"
guard let newEntity = NSEntityDescription.entity(forEntityName: entityName, in: context) else {
return
}
let newRecipe = NSManagedObject(entity: newEntity, insertInto: context)
let name = tf_one.text
let id = recipeId
let category = 1
let persons = 2
newRecipe.setValue(name, forKey: "name")
newRecipe.setValue(id, forKey: "id")
newRecipe.setValue(category, forKey: "category")
newRecipe.setValue(persons, forKey: "persons")
do {
try context.save()
print("Gespeichert!")
let vc: ViewController!
vc = ViewController()
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: false)
} catch {
print(error)
}*/
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print(name_array.count)
return name_array.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifer, for: indexPath) as! IngredientCell
cell.nameLabel.text = name_array[indexPath.row]
cell.descriptionLabel.text = "text"
cell.personsLabel.text = "text"
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let context = appDelegate.persistentContainer.viewContext
let entityName = "/ENTRY/"
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
do {
let results = try context.fetch(request)
guard results.count > 0 else {
return
}
if let deleteEntity = results[indexPath.row] as? NSManagedObject {
context.delete(deleteEntity) //Das Entity ist hier nur markiert als gelöscht, für evt arbeiten am Item
if context.hasChanges {
do {
try context.save()
print("Datensatz gelöscht!")
let vc: ViewController!
vc = ViewController()
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: false)
} catch {
print(error)
}
}
}
} catch {
print(error)
}
}
}
}
import UIKit
import CoreData
class AddNewIngredientViewController: UIViewController {
let viewExample = UIView()
let titleLabel = UILabel()
let tf_one = UITextField()
let unitTicker = UISegmentedControl()
let unitLabel = UILabel()
let slider = UISlider()
let submitButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white.withAlphaComponent(0)
createViewControllerItems()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
func createViewControllerItems() {
// - MARK: View
viewExample.backgroundColor = .white
viewExample.layer.cornerRadius = 15
viewExample.clipsToBounds = true
view.addSubview(viewExample)
viewExample.translatesAutoresizingMaskIntoConstraints = false
viewExample.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -200).isActive = true
viewExample.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
viewExample.widthAnchor.constraint(equalToConstant: 330).isActive = true
viewExample.heightAnchor.constraint(equalToConstant: 350).isActive = true
// - MARK: Titel
titleLabel.text = "Zutat hinzufügen"
titleLabel.textColor = .black
titleLabel.textAlignment = .center
titleLabel.font = UIFont(name: "Chalkduster", size: 24)
view.addSubview(titleLabel)
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
titleLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 50).isActive = true
titleLabel.widthAnchor.constraint(equalToConstant: 250).isActive = true
titleLabel.heightAnchor.constraint(equalToConstant: 40).isActive = true
// - MARK: Überschrift
tf_one.placeholder = "Name"
tf_one.borderStyle = .roundedRect
tf_one.keyboardType = .default
tf_one.spellCheckingType = .yes
tf_one.smartInsertDeleteType = .yes
tf_one.autocorrectionType = .yes
tf_one.autocapitalizationType = .sentences
view.addSubview(tf_one)
tf_one.translatesAutoresizingMaskIntoConstraints = false
tf_one.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
tf_one.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
tf_one.widthAnchor.constraint(equalToConstant: 310).isActive = true
tf_one.heightAnchor.constraint(equalToConstant: 34).isActive = true
// - MARK: Unit Ticker
unitTicker.insertSegment(withTitle: "ml", at: 0, animated: true)
unitTicker.insertSegment(withTitle: "mg", at: 1, animated: true)
unitTicker.insertSegment(withTitle: "unit", at: 2, animated: true)
unitTicker.addTarget(self, action: #selector(updateLabel), for: UIControl.Event.allEvents)
view.addSubview(unitTicker)
unitTicker.translatesAutoresizingMaskIntoConstraints = false
unitTicker.topAnchor.constraint(equalTo: view.topAnchor, constant: 150).isActive = true
unitTicker.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// - MARK: Slider
slider.maximumValue = 10
slider.addTarget(self, action: #selector(updateLabel), for: UIControl.Event.allEvents)
view.addSubview(slider)
slider.translatesAutoresizingMaskIntoConstraints = false
slider.topAnchor.constraint(equalTo: view.topAnchor, constant: 200).isActive = true
slider.widthAnchor.constraint(equalToConstant: 310).isActive = true
slider.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
// - MARK: Bestätigen
submitButton.layer.cornerRadius = 20
submitButton.clipsToBounds = true
submitButton.backgroundColor = .lightGray
submitButton.setTitle("ok", for: UIControl.State.normal)
submitButton.titleLabel?.font = UIFont(name: "Chalkduster", size: 24)
submitButton.addTarget(self, action: #selector(save), for: .touchUpInside)
view.addSubview(submitButton)
submitButton.translatesAutoresizingMaskIntoConstraints = false
submitButton.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 100).isActive = true
submitButton.topAnchor.constraint(equalTo: slider.bottomAnchor, constant: 50).isActive = true
submitButton.widthAnchor.constraint(equalToConstant: 40).isActive = true
submitButton.heightAnchor.constraint(equalToConstant: 40).isActive = true
}
#objc func updateLabel() {
unitLabel.textAlignment = .center
if unitTicker.selectedSegmentIndex == 0{
unitLabel.text = "\(Int(slider.value)) ml"
slider.maximumValue = 1000
}else if unitTicker.selectedSegmentIndex == 1{
unitLabel.text = "\(Int(slider.value)) mg"
slider.maximumValue = 1000
}else if unitTicker.selectedSegmentIndex == 2{
unitLabel.text = "\(Int(slider.value)) unit"
slider.maximumValue = 10
}
view.addSubview(unitLabel)
unitLabel.translatesAutoresizingMaskIntoConstraints = false
unitLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 230).isActive = true
unitLabel.widthAnchor.constraint(equalToConstant: 310).isActive = true
unitLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
#objc func save() {
let viewController = AddNewRecipeViewController()
viewController.name_array.append(tf_one.text!)
print(viewController.name_array)
dismiss(animated: true, completion: nil)
}
}
Thanks!
Tom
You can pass data between two viewController by using the delegate method or NSNotificaton. For more info visit about NSNotification: https://developer.apple.com/documentation/foundation/nsnotification
For delegate method you can check https://medium.com/#jamesrochabrun/implementing-delegates-in-swift-step-by-step-d3211cbac3ef

Struggling to adjust cell height with increase in content

I have been struggling greatly almost regularly to be able to create a cell whose height adjusts with content while trying to do it programatically, some things i am trying are , image shows the problem
use below function
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
2)Use this in viewDidLoad
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 100
Setting bottom and top constraints to equal rather then not equal
Below i paste some code to show my struggle or trying every thing to get the cell to expand with content, which it does. not, can any one please suggest some ways to achieve it
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
let cell = restaurantMainTable.dequeueReusableCell(withIdentifier: String(describing: RestaurantMainViewCells.self), for: indexPath) as! RestaurantMainViewCells
cell.heightAnchor.constraint(greaterThanOrEqualToConstant: 60).isActive = true
view.addSubview(cell)
view.addSubview(cell.contentView)
view.addSubview(cell.restaurantName)
view.addSubview(cell.restaurantType)
view.addSubview(cell.restaurantLocation)
view.addSubview(cell.restaurantMiniImage)
view.addSubview(cell.restaurantHeartImage)
cell.restaurantHeartImage.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantMiniImage.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantName.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantLocation.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantType.translatesAutoresizingMaskIntoConstraints = false
//Fonts
let font = UIFont(name: "Rubik-Medium", size: 18)
let fontMetrics = UIFontMetrics(forTextStyle: .body)
let labels = [cell.restaurantName, cell.restaurantLocation, cell.restaurantType]
labels.forEach { label in
label.font = fontMetrics.scaledFont(for: font!)
}
let stackLabels = UIStackView()
view.addSubview(stackLabels)
stackLabels.alignment = .top
stackLabels.distribution = .fill
stackLabels.spacing = 5
stackLabels.axis = .vertical
stackLabels.addArrangedSubview(cell.restaurantName)
stackLabels.addArrangedSubview(cell.restaurantType)
stackLabels.addArrangedSubview(cell.restaurantLocation)
let stackImage = UIStackView()
view.addSubview(stackImage)
stackLabels.translatesAutoresizingMaskIntoConstraints = false
stackImage.alignment = .top
stackImage.distribution = .fill
stackImage.axis = .horizontal
stackImage.spacing = 5
cell.restaurantMiniImage.heightAnchor.constraint(equalToConstant: 60).isActive = true
cell.restaurantMiniImage.widthAnchor.constraint(equalToConstant: 60).isActive = true
cell.restaurantMiniImage.layer.cornerRadius = 30
cell.restaurantMiniImage.clipsToBounds = true
cell.restaurantHeartImage.heightAnchor.constraint(equalToConstant: 20).isActive = true
cell.restaurantHeartImage.widthAnchor.constraint(equalToConstant: 20).isActive = true
cell.restaurantHeartImage.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
cell.restaurantHeartImage.topAnchor.constraint(equalTo: cell.topAnchor, constant: 20).isActive = true
stackImage.addArrangedSubview(cell.restaurantMiniImage)
stackImage.addArrangedSubview(stackLabels)
view.addSubview(stackImage)
stackImage.translatesAutoresizingMaskIntoConstraints = false
stackImage.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 10).isActive = true
stackImage.topAnchor.constraint(greaterThanOrEqualTo: cell.topAnchor, constant: 10).isActive = true
// stackImage.topAnchor.constraint(equalTo: cell.topAnchor, constant: 10).isActive = true
stackImage.trailingAnchor.constraint(equalTo: cell.restaurantHeartImage.leadingAnchor, constant: -10).isActive = true
// stackImage.bottomAnchor.constraint(equalTo: cell.bottomAnchor, constant: -10).isActive = true
stackImage.bottomAnchor.constraint(greaterThanOrEqualTo: cell.bottomAnchor, constant: -10).isActive = true
cell.restaurantName.text = restaurants[indexPath.row].name
cell.restaurantType.text = restaurants[indexPath.row].type
cell.restaurantLocation.text = restaurants[indexPath.row].location
cell.restaurantHeartImage.image = UIImage(named: "heart-tick")
if let restaurantImage = restaurants[indexPath.row].image {
cell.restaurantMiniImage.image = UIImage(data: restaurantImage as Data)
}
return cell
default:
fatalError("no data found")
}
}
UPDATE - The whole class
//
// RestaurantMainController.swift
// LaVivaRepeat
//
//
import UIKit
import CoreData
class RestaurantMainController: UIViewController, UITableViewDelegate, UITableViewDataSource, NSFetchedResultsControllerDelegate {
var restaurants: [Restaurant] = []
var fetchResultController: NSFetchedResultsController<Restaurant>!
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return restaurants.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
let restaurantMainTable = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(restaurantMainTable)
//MARK:- add delegates as self, always, else no contact with model will take place
restaurantMainTable.rowHeight = UITableView.automaticDimension
restaurantMainTable.estimatedRowHeight = 60
self.restaurantMainTable.delegate = self
self.restaurantMainTable.dataSource = self
self.restaurantMainTable.separatorStyle = .singleLine
//MARK:- create a view to show when no records are there
let backGroundView = UIView()
view.addSubview(backGroundView)
backGroundView.heightAnchor.constraint(equalToConstant: 500).isActive = true
let backGroundImage = UIImageView()
backGroundImage.translatesAutoresizingMaskIntoConstraints = false
backGroundView.translatesAutoresizingMaskIntoConstraints = false
backGroundImage.heightAnchor.constraint(equalToConstant: 300).isActive = true
backGroundImage.widthAnchor.constraint(equalToConstant: 320).isActive = true
backGroundImage.image = UIImage(named: "empty")
backGroundView.addSubview(backGroundImage)
backGroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
backGroundView.topAnchor.constraint(equalTo: view.topAnchor, constant: 90).isActive = true
backGroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 20).isActive = true
restaurantMainTable.backgroundView = backGroundView
restaurantMainTable.backgroundView?.isHidden = true
//MARK:- Add constraints to table
self.restaurantMainTable.translatesAutoresizingMaskIntoConstraints = false
self.restaurantMainTable.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
self.restaurantMainTable.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
self.restaurantMainTable.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
self.restaurantMainTable.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
//MARK:- register RestaurantMainViewCells
self.restaurantMainTable.register(RestaurantMainViewCells.self, forCellReuseIdentifier: String(describing: RestaurantMainViewCells.self))
//MARK:- Get fetch request
let fetchRequest: NSFetchRequest<Restaurant> = Restaurant.fetchRequest()
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
let context = appDelegate.persistentContainer.viewContext
fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
fetchResultController.delegate = self
do {
try fetchResultController.performFetch()
if let fetchObject = fetchResultController.fetchedObjects {
restaurants = fetchObject
}
}
catch {
print(error)
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
restaurantMainTable.rowHeight = UITableView.automaticDimension
switch indexPath.row {
case 0:
let cell = restaurantMainTable.dequeueReusableCell(withIdentifier: String(describing: RestaurantMainViewCells.self), for: indexPath) as! RestaurantMainViewCells
// cell.heightAnchor.constraint(greaterThanOrEqualToConstant: 60).isActive = true
view.addSubview(cell)
view.addSubview(cell.contentView)
view.addSubview(cell.restaurantName)
view.addSubview(cell.restaurantType)
view.addSubview(cell.restaurantLocation)
view.addSubview(cell.restaurantMiniImage)
view.addSubview(cell.restaurantHeartImage)
cell.restaurantHeartImage.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantMiniImage.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantName.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantLocation.translatesAutoresizingMaskIntoConstraints = false
cell.restaurantType.translatesAutoresizingMaskIntoConstraints = false
//Fonts
let font = UIFont(name: "Rubik-Medium", size: 18)
let fontMetrics = UIFontMetrics(forTextStyle: .body)
let labels = [cell.restaurantName, cell.restaurantLocation, cell.restaurantType]
labels.forEach { label in
label.font = fontMetrics.scaledFont(for: font!)
}
let stackLabels = UIStackView()
view.addSubview(stackLabels)
stackLabels.alignment = .top
stackLabels.distribution = .fill
stackLabels.spacing = 5
stackLabels.axis = .vertical
stackLabels.addArrangedSubview(cell.restaurantName)
stackLabels.addArrangedSubview(cell.restaurantType)
stackLabels.addArrangedSubview(cell.restaurantLocation)
let stackImage = UIStackView()
view.addSubview(stackImage)
stackLabels.translatesAutoresizingMaskIntoConstraints = false
stackImage.alignment = .top
stackImage.distribution = .fill
stackImage.axis = .horizontal
stackImage.spacing = 5
cell.restaurantMiniImage.heightAnchor.constraint(equalToConstant: 60).isActive = true
cell.restaurantMiniImage.widthAnchor.constraint(equalToConstant: 60).isActive = true
cell.restaurantMiniImage.layer.cornerRadius = 30
cell.restaurantMiniImage.clipsToBounds = true
cell.restaurantHeartImage.heightAnchor.constraint(equalToConstant: 20).isActive = true
cell.restaurantHeartImage.widthAnchor.constraint(equalToConstant: 20).isActive = true
cell.restaurantHeartImage.trailingAnchor.constraint(equalTo: cell.trailingAnchor, constant: -10).isActive = true
cell.restaurantHeartImage.topAnchor.constraint(equalTo: cell.topAnchor, constant: 20).isActive = true
stackImage.addArrangedSubview(cell.restaurantMiniImage)
stackImage.addArrangedSubview(stackLabels)
view.addSubview(stackImage)
stackImage.translatesAutoresizingMaskIntoConstraints = false
stackImage.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 10).isActive = true
stackImage.topAnchor.constraint(greaterThanOrEqualTo: cell.topAnchor, constant: 10).isActive = true
// stackImage.topAnchor.constraint(equalTo: cell.topAnchor, constant: 10).isActive = true
stackImage.trailingAnchor.constraint(equalTo: cell.restaurantHeartImage.leadingAnchor, constant: -10).isActive = true
// stackImage.bottomAnchor.constraint(equalTo: cell.bottomAnchor, constant: -10).isActive = true
stackImage.bottomAnchor.constraint(greaterThanOrEqualTo: cell.bottomAnchor, constant: -10).isActive = true
cell.restaurantName.text = restaurants[indexPath.row].name
cell.restaurantType.text = restaurants[indexPath.row].type
cell.restaurantLocation.text = restaurants[indexPath.row].location
cell.restaurantHeartImage.image = UIImage(named: "heart-tick")
if let restaurantImage = restaurants[indexPath.row].image {
cell.restaurantMiniImage.image = UIImage(data: restaurantImage as Data)
}
return cell
default:
fatalError("no data found")
}
}
//MARK:- Make custom navigation bar large font size and use rubik fonts
override func viewWillAppear(_ animated: Bool) {
navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.topItem?.title = "LaViva Hotel"
navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.hidesBarsOnSwipe = true
if let customFont = UIFont(name: "Rubik-Medium", size: 40) {
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(red: 200/255, green: 70/255, blue: 70/255, alpha: 1), NSAttributedString.Key.font: customFont]
}
//MARK:- for empty table
if restaurants.count > 0 {
self.restaurantMainTable.backgroundView?.isHidden = true
self.restaurantMainTable.separatorStyle = .singleLine
}
else {
self.restaurantMainTable.backgroundView?.isHidden = false
self.restaurantMainTable.separatorStyle = .none
}
//MARK:- make an + button appear on top left
let addButton = UIBarButtonItem(image: UIImage(named: "plus"), style: .plain, target: self, action: #selector(addNewRestaurant))
//navigationController?.navigationItem.rightBarButtonItem = addButton
self.navigationItem.rightBarButtonItem = addButton
}
//MARK:- addNewRestaurant function
#objc func addNewRestaurant() {
let pushController = RestaurantAddController()
navigationController?.pushViewController(pushController, animated: true)
}
//MARK:- try and show cell and tower as default or dark done here
override var preferredStatusBarStyle: UIStatusBarStyle {
return .default
}
//add update delete
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
restaurantMainTable.beginUpdates()
}
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
switch type {
case .insert:
if let newIndexPath = newIndexPath {
restaurantMainTable.insertRows(at: [newIndexPath], with: .fade)
}
case .delete:
if let indexPath = indexPath {
restaurantMainTable.deleteRows(at: [indexPath], with: .fade)
}
case .update:
if let indexPath = indexPath {
restaurantMainTable.reloadRows(at: [indexPath], with: .fade)
}
default:
restaurantMainTable.reloadData()
}
if let fetchedObjects = controller.fetchedObjects {
restaurants = fetchedObjects as! [Restaurant]
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
restaurantMainTable.endUpdates()
}
//MARK:- left swipr delete
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (action, view, completionHandler) in
if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
let context = appDelegate.persistentContainer.viewContext
let restaurantsToDelete = self.fetchResultController.object(at: indexPath)
context.delete(restaurantsToDelete)
appDelegate.saveContext()
}
completionHandler(true)
}
let swipeConfiguration: UISwipeActionsConfiguration
swipeConfiguration = UISwipeActionsConfiguration(actions: [deleteAction])
return swipeConfiguration
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
UPDATE
import UIKit
class RestaurantMainViewCells: UITableViewCell {
var restaurantMiniImage = UIImageView()
var restaurantHeartImage = UIImageView()
var restaurantName = UILabel()
var restaurantType = UILabel()
var restaurantLocation = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
All of your cell setup - adding and constraining UI elements - should be done in your cell class. Absolutely NOT in cellForRowAt.
You would do well to go through a few tutorials on creating dynamic cells.
But, to give you an idea, here is your code modified so you can see what's happening:
struct Restaurant {
var name: String = ""
var type: String = ""
var location: String = ""
// however you have your image information stored
//var image
}
class RestaurantMainViewCells: UITableViewCell {
var restaurantMiniImage = UIImageView()
var restaurantHeartImage = UIImageView()
var restaurantName = UILabel()
var restaurantType = UILabel()
var restaurantLocation = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func commonInit() -> Void {
// so we can see the image view frames without actual images...
restaurantMiniImage.backgroundColor = .green
restaurantHeartImage.backgroundColor = .red
var font: UIFont = UIFont.systemFont(ofSize: 18)
if let f = UIFont(name: "Rubik-Medium", size: 18) {
font = f
}
let fontMetrics = UIFontMetrics(forTextStyle: .body)
let labels = [restaurantName, restaurantLocation, restaurantType]
labels.forEach { label in
label.font = fontMetrics.scaledFont(for: font)
// so we can see label frames...
label.backgroundColor = .yellow
}
let stackLabels = UIStackView()
stackLabels.alignment = .fill
stackLabels.distribution = .fill
stackLabels.spacing = 5
stackLabels.axis = .vertical
stackLabels.addArrangedSubview(restaurantName)
stackLabels.addArrangedSubview(restaurantType)
stackLabels.addArrangedSubview(restaurantLocation)
let stackImage = UIStackView()
stackImage.alignment = .top
stackImage.distribution = .fill
stackImage.axis = .horizontal
stackImage.spacing = 5
restaurantMiniImage.layer.cornerRadius = 30
restaurantMiniImage.clipsToBounds = true
stackImage.addArrangedSubview(restaurantMiniImage)
stackImage.addArrangedSubview(stackLabels)
contentView.addSubview(stackImage)
contentView.addSubview(restaurantHeartImage)
restaurantHeartImage.translatesAutoresizingMaskIntoConstraints = false
stackImage.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// mini image 60x60
restaurantMiniImage.heightAnchor.constraint(equalToConstant: 60),
restaurantMiniImage.widthAnchor.constraint(equalToConstant: 60),
// heart image 20 x 20
restaurantHeartImage.heightAnchor.constraint(equalToConstant: 20),
restaurantHeartImage.widthAnchor.constraint(equalToConstant: 20),
// heart image top+20 trailing-10
restaurantHeartImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
restaurantHeartImage.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
// horizontal stack top / leading / bottom and trailinh to heart image
// all with 10-pts "padding"
stackImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
stackImage.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
stackImage.trailingAnchor.constraint(equalTo: restaurantHeartImage.leadingAnchor, constant: -10),
stackImage.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10),
])
}
}
class RestaurantMainController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var restaurants: [Restaurant] = []
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return restaurants.count
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
let restaurantMainTable = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(restaurantMainTable)
//MARK:- add delegates as self, always, else no contact with model will take place
restaurantMainTable.estimatedRowHeight = 60
self.restaurantMainTable.delegate = self
self.restaurantMainTable.dataSource = self
self.restaurantMainTable.separatorStyle = .singleLine
//MARK:- Add constraints to table
self.restaurantMainTable.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
restaurantMainTable.topAnchor.constraint(equalTo: view.topAnchor),
restaurantMainTable.bottomAnchor.constraint(equalTo: view.bottomAnchor),
restaurantMainTable.leadingAnchor.constraint(equalTo: view.leadingAnchor),
restaurantMainTable.trailingAnchor.constraint(equalTo: view.trailingAnchor),
])
//MARK:- register RestaurantMainViewCells
self.restaurantMainTable.register(RestaurantMainViewCells.self, forCellReuseIdentifier: String(describing: RestaurantMainViewCells.self))
//MARK:- Get fetch request
// I don't have your "fetch" data, so I'm just adding a couple restaurants here
restaurants.append(Restaurant(name: "Cafe De Loir", type: "Chinese Cousine", location: "Hong Kong"))
restaurants.append(Restaurant(name: "Bob's Cafe", type: "Japanese Cousine", location: "Tokyo"))
restaurants.append(Restaurant(name: "Mary's Restaurant", type: "Home Cooking", location: "Dallas, Texas"))
// let fetchRequest: NSFetchRequest<Restaurant> = Restaurant.fetchRequest()
// let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
// fetchRequest.sortDescriptors = [sortDescriptor]
//
// if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
// let context = appDelegate.persistentContainer.viewContext
// fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
// fetchResultController.delegate = self
//
// do {
// try fetchResultController.performFetch()
// if let fetchObject = fetchResultController.fetchedObjects {
// restaurants = fetchObject
// }
// }
//
// catch {
// print(error)
// }
// }
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: RestaurantMainViewCells.self), for: indexPath) as! RestaurantMainViewCells
let r = restaurants[indexPath.row]
cell.restaurantName.text = r.name
cell.restaurantType.text = r.type
cell.restaurantLocation.text = r.location
//if let restaurantImage = restaurants[indexPath.row].image {
// cell.restaurantMiniImage.image = UIImage(data: restaurantImage as Data)
//}
cell.restaurantHeartImage.image = UIImage(named: "heart-tick")
return cell
}
}
The result (I don't have your images so the image views have green or red background color):

Align Button To Left Side Of UITableView Cell Programmatically Swift

I'm creating a simple app using Swift 5, Xcode 11, and a ui table view controller. Inside the ui table view, I want 2 buttons: One button on the left of my table view, the other on the right. I have tried many other related/similar question's answers, but all of them failed(probably because 1. Too Old, 2. Answer written in OBJ-C).
Here's my Table View Controller:
import UIKit
#objcMembers class CustomViewController: UITableViewController {
var tag = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
// 3
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tag = tag + 1
let cell = tableView.dequeueReusableCell(withIdentifier: "themeCell", for: indexPath) as! ThemeCell
var cellButton: UIButton!
cellButton = UIButton(frame: CGRect(x: 5, y: 5, width: 50, height: 30))
cell.addSubview(cellButton)
cell.img.image = UIImage(named: SingletonViewController.themes[indexPath.row])
cell.accessoryView = cellButton
cellButton.backgroundColor = UIColor.red
cellButton.tag = tag
return cell
}
}
Here's what I'm currently getting:
add below code for apply constraint worked
let cellButton = UIButton(frame: CGRect.zero)
cellButton.translatesAutoresizingMaskIntoConstraints = false
cell.addSubview(cellButton)
cell.accessoryView = cellButton
cellButton.backgroundColor = UIColor.red
cellButton.leadingAnchor.constraint(equalTo: cell.leadingAnchor, constant: 5).isActive = true
cellButton.topAnchor.constraint(equalTo: cell.topAnchor, constant: 5).isActive = true
cellButton.widthAnchor.constraint(equalToConstant: 50).isActive = true
cellButton.heightAnchor.constraint(equalToConstant: 30).isActive = true
You can achieve right and left align button from constraints.
Below is my code to align view right or left.
override func viewDidLoad() {
let leftButton = UIButton(type: .custom)
leftButton.backgroundColor = UIColor.red
self.view.addSubview(leftButton)
leftButton.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraint = leftButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20)
let verticalConstraint = leftButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
let widthConstraint = leftButton.widthAnchor.constraint(equalToConstant: 100)
let heightConstraint = leftButton.heightAnchor.constraint(equalToConstant: 100)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint, widthConstraint, heightConstraint])
let rightButton = UIButton(type: .custom)
rightButton.backgroundColor = UIColor.red
self.view.addSubview(rightButton)
rightButton.translatesAutoresizingMaskIntoConstraints = false
let horizontalConstraintRight = rightButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
let verticalConstraintRight = rightButton.centerYAnchor.constraint(equalTo: view.centerYAnchor)
let widthConstraintRight = rightButton.widthAnchor.constraint(equalToConstant: 100)
let heightConstraintRight = rightButton.heightAnchor.constraint(equalToConstant: 100)
NSLayoutConstraint.activate([horizontalConstraintRight, verticalConstraintRight, widthConstraintRight, heightConstraintRight])
}
[![Left and Right Aligned View Constraints][1]][1]
[1]: https://i.stack.imgur.com/tMJ8N.jpg
As the cell is getting reuse, you have to put buttons in your xib file. You should not make a button every time and add it in a cell. Try this by adding a button in xib.
class ThemeCell: UITableViewCell {
//MARK:- Initialize View
private let button : UIButton = {
let button = UIButton()
button.setTitle("Hello", .normal)
button.backgroundColor = .red
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
//MARK:- View Life Cycle
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setup()
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
selectionStyle = .none
}
//MARK:- User Defined Function
private func setup() {
addSubView(button)
button.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
button.topAnchor.constraint(equalTo: topAnchor, constant: 20).isActive = true
button.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20).isActive = true
}
}
You can use AutoLayout Constraints like this to setup the button. No need to call it in the cellForRow method.

How to add a UICollectionView to a container programmatically?

I'm new to IOS development.
The followings are what I want to implement
- Have a two container in the main view
- In the first container, add a UICollectionView
- In the second container, add a UITableView
This is the code that I've done so far.
Main View:
class MainViewController:UIViewController {
let itemView:UIView = {
let itemContainerView = UIView()
itemContainerView.backgroundColor = UIColor.lightGray
let collectionView = CollectionViewController()
itemContainerView.addSubview(collectionView.view)
itemContainerView.translatesAutoresizingMaskIntoConstraints = false
return itemContainerView
}()
let tableView:UIView = {
let tableContainerView = UIView()
tableContainerView.backgroundColor = UIColor.gray
tableContainerView.translatesAutoresizingMaskIntoConstraints = false
return tableContainerView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
view.addSubview(itemView)
view.addSubview(tableView)
setupItemView()
setupTableView()
}
func setupItemView(){
itemView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
itemView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
itemView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 2/3).isActive = true
itemView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
}
func setupTableView() {
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: itemView.rightAnchor).isActive = true
tableView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 1/3).isActive = true
tableView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
}
}
CollectionViewController:
class CollectionViewController:UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
let cellId = "CellId"
var colView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 111, height: 111)
colView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
colView.delegate = self
colView.dataSource = self
colView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
colView.backgroundColor = UIColor.white
colView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(colView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = UIColor.brown
return cell
}
}
I could see my main screen has two container but couldn't see 10 collection cells.
Could anyone advise me to the right direction? Thanks in advance.
UPDATED
When I set MainViewController as the initial view, it's properly working.
However, in my project, MainViewController is not the initial view.
The flow is;
1. User login
2. Dashboard with a button will appear
3. Clicking button will navigate the user to MainViewController.
Here's my Dashboard class
class DashboardController: UIViewController{
let orderBtn:UIButton = {
let button = UIButton(type: .system)
button.backgroundColor = UIColor.init(red: 173/255, green: 184/255, blue: 255/255, alpha: 1)
button.layer.cornerRadius = 5
button.setTitle("Select Item" , for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(self, action: #selector(handleOrderNavigation), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
view.addSubview(orderBtn)
setupOrderBtn()
}
func handleOrderNavigation() {
let mainViewController= MainViewController()
let mainViewNavController= UINavigationController(rootViewController: mainViewController)
self.present(mainViewNavController, animated: false, completion: nil)
}
}
Your code is proper working. here is the output I got from your collectionView code work.
Suggestion
Check view hierarchy of your UI and see is there is any collectionView present in your UI.
Ensure your methods are properly calling. Check it by adding break point.
Edit
You declaration of MainViewController is wrong in button action.
Instead of present MainViewController use push to MainViewController
Be ensure your button action method is properly calling on button click.
Try to call reloadData at some point after the view is loaded.

Constraints not changing when user cancels searching

So I have a search icon as my right bar button item. When the user taps the icon, it allows the user to search and only show certain values in the tableview. It also hides the nav bar buttons at the top and the filterBar just below the navigation controller
func setupNavBarButtons() {
let searchImage = UIImage(named: "search_icon")?.withRenderingMode(.alwaysOriginal)
let searchBarButtonItem = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(handleSearch))
navigationItem.rightBarButtonItem = searchBarButtonItem
setupFilterButton()
}
filter bar and navbar items to be hidden while searching like so:
func handleSearch() {
searchController.searchBar.isHidden = false
navigationItem.titleView = searchController.searchBar
searchController.searchBar.becomeFirstResponder()
navigationItem.rightBarButtonItems = nil
navigationItem.leftBarButtonItems = nil
filterBar.isHidden = true
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
}
And then it to reappear again once user stops searching, like so:
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
setupNavBarButtons()
searchController.searchBar.isHidden = true
filterBar.isHidden = false
tableView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
// Also tried tableView.topAnchor.constraint(equalTo: filterBar.bottomAnchor).isActive = true
}
Before Search:
During Search
After search: As you can see the tableview doesn't return to where it originally was. The filterBar is the gray view with 'Map' and 'Location'
Still got the same issue so I've uploaded my project here:
https://github.com/lukejones1/bug
At first, You added 'height' layout constraint with 40 px.
and you added 'height' layout constraint with 0 px when user clicked search button.
and again, you added 'height' layout constraint with 40 px when user clicked cancel button.
You need to reuse the layout constraint.
class ViewController: UIViewController {
var filterBarHeightLC : NSLayoutConstraint?
lazy var tableView : UITableView = {
let tv = UITableView()
tv.register(UITableViewCell.self, forCellReuseIdentifier: "cellId")
tv.layoutMargins = UIEdgeInsets.zero
tv.separatorInset = UIEdgeInsets.zero
tv.backgroundColor = .red
tv.translatesAutoresizingMaskIntoConstraints = false
return tv
}()
lazy var filterBar : UIView = {
let bar = UIView()
bar.backgroundColor = .blue
bar.translatesAutoresizingMaskIntoConstraints = false
return bar
}()
fileprivate lazy var filterButton : UIButton = {
let button = UIButton()
button.setTitleColor(UIColor.white, for: UIControlState())
button.setTitle("Filter", for: UIControlState())
button.contentHorizontalAlignment = UIControlContentHorizontalAlignment.left
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
fileprivate lazy var searchController: UISearchController = {
let sc = UISearchController(searchResultsController: nil)
sc.dimsBackgroundDuringPresentation = false
sc.hidesNavigationBarDuringPresentation = false
sc.searchResultsUpdater = self
sc.delegate = self
sc.view.tintColor = UIColor.white
sc.searchBar.tintColor = UIColor.white
sc.searchBar.delegate = self
return sc
}()
func setupNavBarButtons() {
let searchBarButtonItem = UIBarButtonItem(title: "Search", style: .plain, target: self, action: #selector(handleSearch))
navigationItem.rightBarButtonItem = searchBarButtonItem
setupFilterButton()
}
func setupFilterButton() {
let containerView = UIView()
containerView.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
containerView.addSubview(filterButton)
filterButton.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
filterButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
let filterBarButtonItem = UIBarButtonItem(customView: containerView)
navigationItem.leftBarButtonItem = filterBarButtonItem
}
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
setupNavBarButtons()
view.backgroundColor = .white
}
func handleSearch() {
searchController.searchBar.isHidden = false
navigationItem.titleView = searchController.searchBar
searchController.searchBar.becomeFirstResponder()
navigationItem.rightBarButtonItems = nil
navigationItem.leftBarButtonItems = nil
// changed!
filterBarHeightLC?.constant = 0
}
func setupViews() {
view.addSubview(filterBar)
view.addSubview(tableView)
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: filterBar.bottomAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
filterBar.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
filterBar.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
filterBar.topAnchor.constraint(equalTo: view.topAnchor, constant: 64).isActive = true
// changed!
filterBarHeightLC = filterBar.heightAnchor.constraint(equalToConstant: 40)
filterBarHeightLC?.isActive = true
}
extension ViewController: UISearchControllerDelegate, UISearchResultsUpdating, UISearchBarDelegate {
func filteredContentForSearchText(_ searchText: String, scope: String = "All") {
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
setupNavBarButtons()
searchController.searchBar.isHidden = true
// changed!
filterBarHeightLC?.constant = 40
}
func updateSearchResults(for searchController: UISearchController) {
filteredContentForSearchText(searchController.searchBar.text!)
}
}
Have a fun coding! :)

Resources