Design the custom table view cell programatically - swift

I created table view cell programmatically and set the constrains as well.It is able to display the image , firstname , lastname property into cell but when I added new label with values , it not displaying the values .
Here is the cell code .
import UIKit
class PeopleCell: UITableViewCell {
static let identifier = "PeopleCell"
let containerView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true // this will make sure its children do not go out of the boundary
return view
}()
let profileImageView:UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFill // image will never be strecthed vertially or horizontally
img.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
img.layer.cornerRadius = 35
img.clipsToBounds = true
return img
}()
let firstnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 20)
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let lastnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
label.textColor = .white
label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
label.layer.cornerRadius = 5
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let jobTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 20)
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(profileImageView)
containerView.addSubview(firstnameTitleLabel)
containerView.addSubview(lastnameTitleLabel)
containerView.addSubview(jobTitleLabel)
self.contentView.addSubview(containerView)
profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant:70).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant:70).isActive = true
containerView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:self.profileImageView.trailingAnchor, constant:10).isActive = true
containerView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
firstnameTitleLabel.topAnchor.constraint(equalTo:self.containerView.topAnchor).isActive = true
firstnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
firstnameTitleLabel.trailingAnchor.constraint(equalTo:self.containerView.trailingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
jobTitleLabel.topAnchor.constraint(equalTo:self.lastnameTitleLabel.bottomAnchor).isActive = true
jobTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
jobTitleLabel.topAnchor.constraint(equalTo:self.lastnameTitleLabel.bottomAnchor).isActive = true
jobTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(firstName: String, lastName: String,jobtitle: String ) {
firstnameTitleLabel.text = "Firstname :\(firstName)"
lastnameTitleLabel.text = "Lastname : \(lastName)"
jobTitleLabel.text = "Occupation : \(jobtitle)"
}
func configureImageCell(row: Int, viewModel: ViewModel) {
profileImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.profileImageView.image = image
}
}
}
Here is the view controller code .
import UIKit
import Combine
class PeopleViewController: UIViewController {
var coordinator: PeopleBaseCoordinator?
init(coordinator: PeopleBaseCoordinator) {
super.init(nibName: nil, bundle: nil)
self.coordinator = coordinator
title = "People"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let viewModel = ViewModel()
private var subscribers = Set<AnyCancellable>()
private var activityIndicator = UIActivityIndicatorView(style: .medium)
private lazy var tableView: UITableView = {
let tableview = UITableView()
tableview.translatesAutoresizingMaskIntoConstraints = false
tableview.dataSource = self
tableview.prefetchDataSource = self
tableview.showsVerticalScrollIndicator = false
tableview.register(PeopleCell.self, forCellReuseIdentifier: PeopleCell.identifier)
return tableview
}()
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
setUpUI()
setUpBinding()
self.activityIndicator.stopAnimating()
// Do any additional setup after loading the view.
}
private func setUpUI() {
view.backgroundColor = .white
title = "People List "
view.addSubview(activityIndicator)
view.addSubview(tableView)
// self.tableView.rowHeight = 100.00
tableView.rowHeight = UITableView.automaticDimension
tableView.rowHeight = 100
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
private func setUpBinding() {
viewModel
.$peoples
.receive(on : RunLoop.main)
.sink { [weak self ] _ in
self?.tableView.reloadData()
}
.store(in: &subscribers)
viewModel.getPeople()
}
}
extension PeopleViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.peoples.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: PeopleCell.identifier, for: indexPath) as? PeopleCell
else { return UITableViewCell() }
let row = indexPath.row
let people = viewModel.peoples[row]
cell.configureCell(firstName: people.firstName, lastName: people.lastName,jobtitle: people.jobtitle)
cell.configureImageCell(row: row, viewModel: viewModel)
return cell
}
}
extension PeopleViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
viewModel.getPeople()
}
}
Here is the screenshot . As it not showing the job title property into cell .

I think your problem is the height of your containerView
containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
I think 40 is to low to show the jobTitleLabel

Related

Simulate a cell like in between two cells and below two cells

I am using tableview and collection view inside to create this screen.
If you look closer in the design..i will have to create an effect of cells going above below or top cell with a corner radius...which simulates like the cells are below and in between two cells...
The same goes for the top area which has a corner radius.
Please guide through a proper way to design this entire screen.
(I am using storyboard and UIKit only...i dont want to use swiftUI)
Various ways to approach this -- here's one...
Four cell types:
"Top" cell
"Categories" cell
"Top Products" cell
"Suggestions" cell
In each cell class, add a UIView with rounded corners - this will hold the "content" of each cell.
Behind the rounded corners view, add a "Top Color" UIView and a a "Bottom Color" UIView.
It looks like this:
When running, we get this result:
Here is some sample code:
class MyBaseCell: UITableViewCell {
var topBotColors: [UIColor] = [.white, .white] {
didSet {
topColorView.backgroundColor = topBotColors[0]
botColorView.backgroundColor = topBotColors[1]
}
}
let theStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 12
return v
}()
let topColorView = UIView()
let botColorView = UIView()
let roundedCornerView = UIView()
var topConstraint: NSLayoutConstraint!
var botConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
[topColorView, botColorView, roundedCornerView].forEach { v in
v.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(v)
}
theStack.translatesAutoresizingMaskIntoConstraints = false
roundedCornerView.addSubview(theStack)
let g = contentView.layoutMarginsGuide
topConstraint = theStack.topAnchor.constraint(equalTo: roundedCornerView.topAnchor, constant: 12.0)
botConstraint = theStack.bottomAnchor.constraint(equalTo: roundedCornerView.bottomAnchor, constant: -12.0)
NSLayoutConstraint.activate([
topColorView.topAnchor.constraint(equalTo: contentView.topAnchor),
topColorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
topColorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
botColorView.topAnchor.constraint(equalTo: topColorView.bottomAnchor),
botColorView.heightAnchor.constraint(equalTo: topColorView.heightAnchor),
botColorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
botColorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
botColorView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
roundedCornerView.topAnchor.constraint(equalTo: g.topAnchor),
roundedCornerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
roundedCornerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
roundedCornerView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
theStack.leadingAnchor.constraint(equalTo: roundedCornerView.leadingAnchor),
theStack.trailingAnchor.constraint(equalTo: roundedCornerView.trailingAnchor),
topConstraint, botConstraint,
])
self.backgroundColor = .clear
contentView.backgroundColor = .clear
}
}
class TopCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add 1 tall label
let v = UILabel()
v.textAlignment = .center
v.text = "Top Cell"
v.textColor = .white
v.font = .systemFont(ofSize: 24.0, weight: .bold)
theStack.addArrangedSubview(v)
// avoid auot-layout complaints
let c = v.heightAnchor.constraint(equalToConstant: 80.0)
c.priority = .required - 1
c.isActive = true
}
}
class CatsCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add a few labels
for i in 1...4 {
let v = UILabel()
v.textAlignment = .center
v.text = "Categories Label \(i)"
theStack.addArrangedSubview(v)
}
roundedCornerView.backgroundColor = .white
roundedCornerView.layer.cornerRadius = 24
}
}
class TopProdsCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add a few labels
for i in 1...3 {
let v = UILabel()
v.textAlignment = .center
v.text = "Top Prods Label \(i)"
v.textColor = .white
theStack.addArrangedSubview(v)
}
roundedCornerView.backgroundColor = .clear
// increase top/bottom "spacing"
topConstraint.constant = 24.0
botConstraint.constant = -24.0
}
}
class SuggestionsCell: MyBaseCell {
override func commonInit() {
super.commonInit()
// let's add a few labels
for i in 1...6 {
let v = UILabel()
v.textAlignment = .center
v.text = "Suggested Label \(i)"
theStack.addArrangedSubview(v)
}
roundedCornerView.backgroundColor = .white
roundedCornerView.layer.cornerRadius = 24
}
}
class SampleTableVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
let myGray: UIColor = .gray
let myBlue: UIColor = UIColor(red: 0.25, green: 0.30, blue: 0.65, alpha: 1.0)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
])
tableView.register(TopCell.self, forCellReuseIdentifier: "topCell")
tableView.register(CatsCell.self, forCellReuseIdentifier: "catCell")
tableView.register(TopProdsCell.self, forCellReuseIdentifier: "prodCell")
tableView.register(SuggestionsCell.self, forCellReuseIdentifier: "suggCell")
tableView.dataSource = self
tableView.delegate = self
let bkv = UIView()
bkv.backgroundColor = myGray
tableView.backgroundView = bkv
tableView.separatorStyle = .none
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let c = tableView.dequeueReusableCell(withIdentifier: "topCell", for: indexPath) as! TopCell
c.topBotColors = [myGray, myGray]
return c
}
if indexPath.row == 1 {
let c = tableView.dequeueReusableCell(withIdentifier: "catCell", for: indexPath) as! CatsCell
c.topBotColors = [myGray, myBlue]
return c
}
if indexPath.row == 2 {
let c = tableView.dequeueReusableCell(withIdentifier: "prodCell", for: indexPath) as! TopProdsCell
c.topBotColors = [myBlue, myBlue]
return c
}
let c = tableView.dequeueReusableCell(withIdentifier: "suggCell", for: indexPath) as! SuggestionsCell
c.topBotColors = [myBlue, myGray]
return c
}
}

Creating custom table View with Cell properties programmatically

I am new to swift . I am trying to create table view and cell programmatically. I want to display the three label properties one below to another . I added the content view with respective label properties . I have set the row height but when I run the app is overlapping.
Here is the my Table view code with view controller .
class RoomViewController: UIViewController {
var coordinator: RoomBaseCoordinator?
init(coordinator: RoomBaseCoordinator) {
super.init(nibName: nil, bundle: nil)
self.coordinator = coordinator
title = "People"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let roomviewModel = RoomViewModel()
private var subscribers = Set<AnyCancellable>()
var activityIndicator = UIActivityIndicatorView(style: .medium)
private lazy var tableView: UITableView = {
let tableview = UITableView()
tableview.translatesAutoresizingMaskIntoConstraints = false
tableview.dataSource = self
tableview.prefetchDataSource = self
tableview.showsVerticalScrollIndicator = false
tableview.register(RoomCellTableViewCell.self, forCellReuseIdentifier: RoomCellTableViewCell.identifier)
return tableview
}()
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
setUpUI()
setUpBinding()
self.activityIndicator.stopAnimating()
}
private func setUpUI() {
view.backgroundColor = .white
title = "Room List "
view.addSubview(tableView)
tableView.rowHeight = 100
// create constraints
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
private func setUpBinding() {
roomviewModel
.$rooms
.receive(on : RunLoop.main)
.sink { [weak self ] _ in
self?.tableView.reloadData()
}
.store(in: &subscribers)
roomviewModel.getRoom()
}
}
extension RoomViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return roomviewModel.rooms.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: RoomCellTableViewCell.identifier, for: indexPath) as? RoomCellTableViewCell
else { return UITableViewCell() }
let row = indexPath.row
let room = roomviewModel.rooms[row]
cell.configureCell(createdAt: room.createdAt, IsOccupied: room.isOccupied, maxOccupancy: String(room.maxOccupancy), id: room.id)
return cell
}
}
extension RoomViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
roomviewModel.getRoom()
}
}
Here is the cell .
class RoomCellTableViewCell: UITableViewCell {
static let identifier = "RoomCell"
private lazy var createdAtLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
label.textAlignment = .left
return label
}()
private lazy var IsOccupiedLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
//label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
label.textAlignment = .left
return label
}()
private lazy var maxOccupancyLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
label.textAlignment = .left
return label
}()
private lazy var idLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = UIFont.boldSystemFont(ofSize: 15)
label.numberOfLines = 0
label.textAlignment = .left
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// self.contentView.addSubview(containerView)
contentView.addSubview(createdAtLabel)
contentView.addSubview(IsOccupiedLabel)
contentView.addSubview(maxOccupancyLabel)
createdAtLabel.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
createdAtLabel.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
createdAtLabel.widthAnchor.constraint(equalToConstant:50).isActive = true
createdAtLabel.heightAnchor.constraint(equalToConstant:50).isActive = true
contentView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
contentView.leadingAnchor.constraint(equalTo:self.createdAtLabel.trailingAnchor, constant:10).isActive = true
contentView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
contentView.heightAnchor.constraint(equalToConstant:50).isActive = true
IsOccupiedLabel.topAnchor.constraint(equalTo:self.contentView.topAnchor).isActive = true
IsOccupiedLabel.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor).isActive = true
IsOccupiedLabel.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor).isActive = true
maxOccupancyLabel.topAnchor.constraint(equalTo:self.IsOccupiedLabel.bottomAnchor).isActive = true
maxOccupancyLabel.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor).isActive = true
maxOccupancyLabel.topAnchor.constraint(equalTo:self.IsOccupiedLabel.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(createdAt: String, IsOccupied: Bool, maxOccupancy: String, id : String ) {
createdAtLabel.text = "CreatedAt :\(createdAt)"
IsOccupiedLabel.text = "IsOccupied : \(IsOccupied)"
maxOccupancyLabel.text = "MaxOccupancy : \(maxOccupancy)"
idLabel.text = "Id : \(id)"
}
}
Here is the result .
In setUpUI() method of your RoomViewController class, set tableView's rowHeight to UITableView.automaticDimension and estimatedRowHeight to 100.
import UIKit
class RoomViewController: UIViewController {
private func setUpUI() {
view.backgroundColor = .white
title = "Room List "
view.addSubview(tableView)
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableView.automaticDimension
// create constraints
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
And add UIStackView in the RoomCellTableViewCell class as bellow:
import UIKit
class RoomCellTableViewCell: UITableViewCell {
private var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fill
stackView.alignment = .fill
stackView.spacing = 8
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
stackView.leftAnchor.constraint(equalTo: leftAnchor),
stackView.rightAnchor.constraint(equalTo: rightAnchor)
])
stackView.addArrangedSubview(createdAtLabel)
stackView.addArrangedSubview(isOccupiedLabel)
stackView.addArrangedSubview(maxOccupancyLabel)
// stackView.addArrangedSubview(idLabel)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Table View Design overlapping

I am new to swift .I want to display the records with image view in table view cell . I have defined the property with leadingAnchor , trailingAnchor, widthAnchor, heightAnchor with content view . But when I run the app it overlapping the view .
Here is the code in cell .
import UIKit
class PeopleCell: UITableViewCell {
static let identifier = "PeopleCell"
let containerView:UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.clipsToBounds = true // this will make sure its children do not go out of the boundary
return view
}()
let profileImageView:UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFill // image will never be strecthed vertially or horizontally
img.translatesAutoresizingMaskIntoConstraints = false // enable autolayout
img.layer.cornerRadius = 35
img.clipsToBounds = true
return img
}()
let firstnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 20)
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let lastnameTitleLabel:UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 14)
label.textColor = .white
label.backgroundColor = #colorLiteral(red: 0.1764705926, green: 0.4980392158, blue: 0.7568627596, alpha: 1)
label.layer.cornerRadius = 5
label.clipsToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(profileImageView)
containerView.addSubview(firstnameTitleLabel)
containerView.addSubview(lastnameTitleLabel)
self.contentView.addSubview(containerView)
profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant:70).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant:70).isActive = true
containerView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:self.profileImageView.trailingAnchor, constant:10).isActive = true
containerView.trailingAnchor.constraint(equalTo:self.contentView.trailingAnchor, constant:-10).isActive = true
containerView.heightAnchor.constraint(equalToConstant:40).isActive = true
firstnameTitleLabel.topAnchor.constraint(equalTo:self.containerView.topAnchor).isActive = true
firstnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
firstnameTitleLabel.trailingAnchor.constraint(equalTo:self.containerView.trailingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
lastnameTitleLabel.topAnchor.constraint(equalTo:self.firstnameTitleLabel.bottomAnchor).isActive = true
lastnameTitleLabel.leadingAnchor.constraint(equalTo:self.containerView.leadingAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureCell(firstName: String, lastName: String) {
firstnameTitleLabel.text = "Firstname :\(firstName)"
lastnameTitleLabel.text = "Lastname : \(lastName)"
}
func configureImageCell(row: Int, viewModel: ViewModel) {
profileImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.profileImageView.image = image
}
}
}
Here is the view controller code .
import UIKit
import Combine
class PeopleViewController: UIViewController {
var coordinator: PeopleBaseCoordinator?
init(coordinator: PeopleBaseCoordinator) {
super.init(nibName: nil, bundle: nil)
self.coordinator = coordinator
title = "People"
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private let viewModel = ViewModel()
private var subscribers = Set<AnyCancellable>()
var activityIndicator = UIActivityIndicatorView(style: .medium)
private lazy var tableView: UITableView = {
let tableview = UITableView()
tableview.translatesAutoresizingMaskIntoConstraints = false
tableview.dataSource = self
tableview.prefetchDataSource = self
tableview.showsVerticalScrollIndicator = false
tableview.register(PeopleCell.self, forCellReuseIdentifier: PeopleCell.identifier)
return tableview
}()
override func viewDidLoad() {
super.viewDidLoad()
activityIndicator.startAnimating()
setUpUI()
setUpBinding()
self.activityIndicator.stopAnimating()
// Do any additional setup after loading the view.
}
private func setUpUI() {
view.backgroundColor = .white
title = "People List "
view.addSubview(tableView)
tableView.topAnchor.constraint(equalTo:view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo:view.safeAreaLayoutGuide.rightAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor).isActive = true
// Creating constrain for Indecator
activityIndicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(activityIndicator)
activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
private func setUpBinding() {
viewModel
.$peoples
.receive(on : RunLoop.main)
.sink { [weak self ] _ in
self?.tableView.reloadData()
}
.store(in: &subscribers)
viewModel.getPeople()
}
}
extension PeopleViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.peoples.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: PeopleCell.identifier, for: indexPath) as? PeopleCell
else { return UITableViewCell() }
let row = indexPath.row
let people = viewModel.peoples[row]
cell.configureCell(firstName: people.firstName, lastName: people.lastName)
cell.configureImageCell(row: row, viewModel: viewModel)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
extension PeopleViewController: UITableViewDataSourcePrefetching {
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
viewModel.getPeople()
}
}
Here is the result .
This is rather tricky because it seems your constraints are fine, assuming that your tableview height is 100, but the screenshot tableview cells seem a little shorter than 100. Let's assume the cell height is 100 correct.
I suggest you try configuring the imageView (and other views) in override func layoutSubViews(), which is a function that renders whenever the contentView's bound change. It should also be noted that better practice is where the imageSize is relative to the cell/contentView's frame instead of hardcoded values.
So it should look like
import UIKit
class PeopleCell: UITableViewCell {
let profileImageView:UIImageView = {
let img = UIImageView()
return img
}()
override func layoutSubviews() {
super.layoutSubviews()
profileImageView.translatesAutoresizingMaskIntoConstraints = false profileImageView.centerYAnchor.constraint(equalTo:self.contentView.centerYAnchor).isActive = true
profileImageView.leadingAnchor.constraint(equalTo:self.contentView.leadingAnchor, constant:10).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant:self.frame.width * 0.7).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant:self.frame.width * 0.7).isActive = true
//You may want to try with other type of contentMode such as aspectFit, etc
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = self.frame.width / 2
profileImageView.clipsToBounds = true
}
//If above doesn't work, you may want to look into the imageConfiguration function you made and ensure that contentMode is applied properly.
func configureImageCell(row: Int, viewModel: ViewModel) {
profileImageView.image = nil
viewModel
.downloadImage(row: row) { [weak self] data in
let image = UIImage(data: data)
self?.profileImageView.image = image
self?.profileImageView.contentMode = .scaleAspectFill
}
}
If all of the above code doesn't work, try to find the profileImageView size values by using breakpoints or ViewHierarchy within Xcode. To check the height of image or cell itself, they should be sufficient for you to find clues to resolve the issue.
All the best.

Swift: Textviews within UIStackView not displaying

I'm trying to create a basic table that would have 4 columns. I'm approaching this by creating a UITableView with a custom cell which contains a horizontal stack view containing the required text views. Here is my UITableView code:
import UIKit
class HistoryTableViewController: UITableViewController {
let cellID = "HistoryColumns"
struct CellData {
let firstColumn: String?
let secondColumn: String?
let thirdColumn: String?
let fourthColumn: String?
}
var data = [CellData]()
override func viewDidLoad() {
super.viewDidLoad()
data = [CellData.init(firstColumn: "Date", secondColumn: "Flight number", thirdColumn: "Type", fourthColumn: "Pre-refuel FOB (kg)")]
tableView.register(FuelHistoryColumnCells.self, forCellReuseIdentifier: cellID)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return data.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID) as! FuelHistoryColumnCells
cell.firstColumn = data[indexPath.row].firstColumn
cell.secondColumn = data[indexPath.row].secondColumn
cell.thirdColumn = data[indexPath.row].thirdColumn
cell.fourthColumn = data[indexPath.row].fourthColumn
return cell
}
}
And this is my custom cell code:
import UIKit
class FuelHistoryColumnCells: UITableViewCell {
var firstColumn: String?
var secondColumn: String?
var thirdColumn: String?
var fourthColumn: String?
lazy var firstColumnView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = .green
return textView
}()
lazy var secondColumnView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = .green
return textView
}()
lazy var thirdColumnView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = .green
return textView
}()
lazy var fourthColumnView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = .green
return textView
}()
lazy var fifthColumnView: UITextView = {
let textView = UITextView()
textView.font = UIFont.systemFont(ofSize: 15)
textView.backgroundColor = .green
return textView
}()
lazy var stackView: UIStackView = {
let stack = UIStackView(arrangedSubviews: [firstColumnView, secondColumnView, thirdColumnView, fourthColumnView])
stack.axis = .horizontal
stack.distribution = .fillEqually
return stack
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(stackView)
}
override func layoutSubviews() {
super.layoutSubviews()
if let firstColumn = firstColumn {
firstColumnView.text = firstColumn
}
if let secondColumn = secondColumn {
secondColumnView.text = secondColumn
}
if let thirdColumn = thirdColumn {
thirdColumnView.text = thirdColumn
}
if let fourthColumn = fourthColumn {
fourthColumnView.text = fourthColumn
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I'm sure I'm missing something obvious here as nothing is showing up on the table view...

fetch data from Firebase using autoID - Xcode

On the top level of my app I have a tableViewController where you can create new jobs that are saved to my firebase database using an autoID.
Here is the JSON
{
"jobInfo" : {
"-L59sEGslWF7HFza26ay" : {
"FPS" : "25",
"director" : "Mike & Jim",
"jobBrand" : "Honda",
"jobName" : "Dreammakers"
},
"-L59sWGEccWMFEeFWyNU" : {
"FPS" : "25",
"director" : "Anthony Test",
"jobBrand" : "WWF",
"jobName" : "Eye"
}
}
}
This is the code that links you to the UITabBarController:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let jobInfo = page_jobTabController()
show(jobInfo, sender: self)
}
You can then click on one of the cells which takes you to a UItabBarViewController that has 4 tabs. In the first tab I have several textFields that lists information about the job.
I am struggling to work out how to send the autoID from the UITableViewController through the UITabBarController to the UIViewController so the textFields can be filled in with the correct information.
Here is a screenshot of the two pages to get an idea of what I want to do.
Sorry to dump all this code below - I am not trying to spam.
This is my dictionary:
class Job: NSObject {
var id: String?
var jobBrand: String?
var jobName : String?
var directorName : String?
var FPSvalue : String?
init(dictionary: [String: AnyObject]) {
self.id = dictionary["id"] as? String
self.jobBrand = dictionary["jobBrand"] as? String
self.jobName = dictionary["jobName"] as? String
self.directorName = dictionary["directorName"] as? String
self.FPSvalue = dictionary["FPSvalue"] as? String
}
}
This is my jobList page (top level)
class page_jobList: UITableViewController {
let cellId = "cellId"
var jobs = [Job]()
override func viewDidLoad() {
super.viewDidLoad()
// NAVIGATION ITEM
navigationItem.title = "Jobs"
navigationController?.navigationBar.prefersLargeTitles = true
tableView.register(JobCell.self, forCellReuseIdentifier: cellId)
// FIREBASE FETCH JOBS
fetchJobs()
}
// FETCH JOBS
func fetchJobs() {
Database.database().reference().child("jobInfo").observe(.childAdded) { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
print (snapshot)
// PROCESSES VALUES RECEIVED FROM SERVER
if ( snapshot.value is NSNull ) {
// DATA WAS NOT FOUND
print("– – – Data was not found – – –")
} else {
let job = Job(dictionary: dictionary)
job.id = snapshot.key
self.jobs.append(job)
//this will crash because of background thread, use dispatch_async to fix
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}
}
}
// AFTER DATA IS FETCHED AND ADD IT TO TABLE VIEW
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return jobs.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
let job = jobs[indexPath.row]
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
cell.textLabel?.text = job.jobBrand
cell.detailTextLabel?.text = job.jobName
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 72
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let jobInfo = page_jobTabController()
jobInfo.job? = jobs[indexPath.row]
show(jobInfo, sender: self)
}
}
class JobCell: UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?){
super .init(style: .subtitle, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implented")
}
}
This is my tabBarController:
class page_jobTabController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// NAVIGATION ITEM
let jobInfo = page_jobInformation()
jobInfo.job? = job!
let shots = page_shotList()
let attachments = page_attachments()
let notes = page_notesList()
jobInfo.tabBarItem.title = "Information"
jobInfo.tabBarItem.image = UIImage(named: "jobInfo")
shots.tabBarItem.title = "Shots"
shots.tabBarItem.image = UIImage(named: "shots")
attachments.tabBarItem.title = "Attachments"
attachments.tabBarItem.image = UIImage(named: "attachments")
notes.tabBarItem.title = "Notes"
notes.tabBarItem.image = UIImage(named: "notes")
viewControllers = [jobInfo, shots, attachments, notes]
}
#IBAction func HandleEdit(sender : UIButton) {
let transition = CATransition()
transition.duration = 0.5
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)
view.window!.layer.add(transition, forKey: kCATransition)
}
}
This is my jobInfo tab ViewController
class page_jobInformation: UIViewController{
// CONTENT CREATION
// GENERAL
let generalTitle: UILabel = {
let generalTitle = UILabel()
generalTitle.font = UIFont(name: "HelveticaNeue", size: 12.0)
generalTitle.text = "GENERAL"
generalTitle.translatesAutoresizingMaskIntoConstraints = false
return generalTitle
}()
let jobBrand: UITextField = {
let jobBrand = UITextField()
//jobBrand.text = "jobBrand"
jobBrand.isUserInteractionEnabled = false
jobBrand.keyboardType = UIKeyboardType.default
jobBrand.translatesAutoresizingMaskIntoConstraints = false
return jobBrand
}()
let jobName: UITextField = {
let jobName = UITextField()
jobName.keyboardType = UIKeyboardType.default
jobName.text = "jobName"
jobName.isUserInteractionEnabled = false
jobName.translatesAutoresizingMaskIntoConstraints = false
return jobName
}()
let directorName: UITextField = {
let directorName = UITextField()
directorName.text = "directorName"
directorName.keyboardType = UIKeyboardType.default
directorName.isUserInteractionEnabled = false
directorName.translatesAutoresizingMaskIntoConstraints = false
return directorName
}()
let AgencyName: UITextField = {
let AgencyName = UITextField()
AgencyName.text = "Agency"
AgencyName.keyboardType = UIKeyboardType.default
AgencyName.isUserInteractionEnabled = false
AgencyName.translatesAutoresizingMaskIntoConstraints = false
return AgencyName
}()
let prodCoName: UITextField = {
let prodCoName = UITextField()
prodCoName.text = "Production Company"
prodCoName.keyboardType = UIKeyboardType.default
prodCoName.isUserInteractionEnabled = false
prodCoName.translatesAutoresizingMaskIntoConstraints = false
return prodCoName
}()
// TECHNICAL
let technicalTitle: UILabel = {
let technicalTitle = UILabel()
technicalTitle.font = UIFont(name: "HelveticaNeue", size: 12.0)
technicalTitle.text = "TECHNICAL"
technicalTitle.translatesAutoresizingMaskIntoConstraints = false
return technicalTitle
}()
lazy var jobSpecsButton: UIButton = {
let jobSpecsButton = UIButton(type: .system)
jobSpecsButton.setTitle("Job Specifications", for: .normal)
jobSpecsButton.titleLabel?.font = UIFont(name: "HelveticaNeue", size: 14.0)
jobSpecsButton.layer.masksToBounds = true
jobSpecsButton.contentHorizontalAlignment = .left
jobSpecsButton.setTitleColor(UIColor.gray, for: UIControlState.normal)
jobSpecsButton.backgroundColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
jobSpecsButton.setTitleColor(.black, for: .normal)
jobSpecsButton.translatesAutoresizingMaskIntoConstraints = false
jobSpecsButton.addTarget(self, action: #selector(HandleJobSpecs), for: .touchUpInside)
return jobSpecsButton
}()
lazy var cameraButton: UIButton = {
let cameraButton = UIButton(type: .system)
cameraButton.setTitle("Camera & Lenses", for: .normal)
cameraButton.titleLabel?.font = UIFont(name: "HelveticaNeue", size: 14.0)
cameraButton.layer.masksToBounds = true
cameraButton.contentHorizontalAlignment = .left
cameraButton.setTitleColor(UIColor.gray, for: UIControlState.normal)
cameraButton.backgroundColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
cameraButton.setTitleColor(.black, for: .normal)
cameraButton.translatesAutoresizingMaskIntoConstraints = false
cameraButton.addTarget(self, action: #selector(HandleCameraLenses), for: .touchUpInside)
return cameraButton
}()
lazy var SKCButton: UIButton = {
let SKCButton = UIButton(type: .system)
SKCButton.setTitle("Shoot Kit Checklist", for: .normal)
SKCButton.titleLabel?.font = UIFont(name: "HelveticaNeue", size: 14.0)
SKCButton.layer.masksToBounds = true
SKCButton.contentHorizontalAlignment = .left
SKCButton.setTitleColor(UIColor.gray, for: UIControlState.normal)
SKCButton.backgroundColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
SKCButton.setTitleColor(.black, for: .normal)
SKCButton.translatesAutoresizingMaskIntoConstraints = false
SKCButton.addTarget(self, action: #selector(HandleSKC), for: .touchUpInside)
return SKCButton
}()
// STACKED VIEWS
lazy var stack:UIStackView = {
let s = UIStackView(frame: self.view.bounds)
s.axis = .vertical
s.distribution = .equalSpacing
s.alignment = .fill
s.spacing = 10
//s.autoresizingMask = [.flexibleWidth, .flexibleHeight]
s.addArrangedSubview(self.generalTitle)
s.addArrangedSubview(self.jobBrand)
s.addArrangedSubview(self.jobName)
s.addArrangedSubview(self.directorName)
s.addArrangedSubview(self.AgencyName)
s.addArrangedSubview(self.prodCoName)
s.addArrangedSubview(self.technicalTitle)
s.addArrangedSubview(self.jobSpecsButton)
s.addArrangedSubview(self.cameraButton)
s.addArrangedSubview(self.SKCButton)
return s
}()
// SUPER VIEW DID LOAD
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.white
}
// VIEW WILL APPEAR
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tabBarController?.navigationItem.title = "Job Information"
self.tabBarController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(HandleEditJob))
view.addSubview(stack)
jobInfoValues()
setupLayout()
}
// OBSERVE JOB
var job: Job?
// FILL IN TEXT FIELDS FROM FIREBASE
func jobInfoValues(){
jobBrand.text = job?.jobBrand
jobName.text = job?.jobName
directorName.text = job?.directorName
}
// BUTTONS & ACTIONS
#IBAction func HandleJobSpecs(sender : UIButton) {
let jobSpecs = page_jobSpecs()
show(jobSpecs, sender: self)
}
#IBAction func HandleCameraLenses(sender : UIButton) {
let cameras = page_camera_lenses()
show(cameras, sender: self)
}
#IBAction func HandleSKC(sender : UIButton) {
let shootKit = page_SKC()
show(shootKit, sender: self)
}
#IBAction func HandleEditJob(sender : UIButton) {
// CHANGE NAVIGATION BAR ITEM
self.tabBarController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(HandleJobEditDone))
// ALLOW TEXT FIELDS TO BE EDITABLE
jobBrand.isUserInteractionEnabled = true
jobName.isUserInteractionEnabled = true
directorName.isUserInteractionEnabled = true
AgencyName.isUserInteractionEnabled = true
prodCoName.isUserInteractionEnabled = true
// ADDING CLEAR BUTTON
jobBrand.clearButtonMode = .always
jobName.clearButtonMode = .always
directorName.clearButtonMode = .always
AgencyName.clearButtonMode = .always
prodCoName.clearButtonMode = .always
}
#IBAction func HandleJobEditDone(sender : UIButton) {
self.tabBarController?.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(HandleEditJob))
jobBrand.isUserInteractionEnabled = false
jobName.isUserInteractionEnabled = false
directorName.isUserInteractionEnabled = false
AgencyName.isUserInteractionEnabled = false
prodCoName.isUserInteractionEnabled = false
// ADDING CLEAR BUTTON
jobBrand.clearButtonMode = .never
jobName.clearButtonMode = .never
directorName.clearButtonMode = .never
AgencyName.clearButtonMode = .never
prodCoName.clearButtonMode = .never
}
// CONSTRAINTS
private func setupLayout(){
// Auto layout constraints for jobInfo
generalTitle.topAnchor.constraint(equalTo: view.topAnchor, constant: 150).isActive = true
generalTitle.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for jobInfo
jobBrand.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for cameras
jobName.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for attachments
directorName.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for attachments
AgencyName.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for attachments
prodCoName.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for attachments
technicalTitle.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for attachments
jobSpecsButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for attachments
cameraButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
// Auto layout constraints for SKC
SKCButton.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 20).isActive = true
SKCButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100).isActive = true
}
}
Please check the codes.
https://github.com/HsiaoAi/JobInfoStackoverflow/tree/master/JobInfoStackoverflow
Make sure your Json decoding is correct, because I found you used"director" in Firebase but "directorName" when init Job
I modified the "fetchJobs()" because I dont have the Firebase plist file
I modified 5 stuff and I marked them in code as "###", you can use search and check them, I hope it works for you too.