How to use autolayout with code - ios

I want to make a custom tableview with autolayout, so how shall I make it with autolayout.
I think it should be something like this:-
self.view.addConstraints([
NSLayoutConstraint(item: square, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .width, multiplier: 1.0, constant: 64),
NSLayoutConstraint(item: square, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: 64),
NSLayoutConstraint(item: square, attribute: .centerX, relatedBy: .equal, toItem: self.view, attribute: .centerX, multiplier: 1.0, constant: 0),
NSLayoutConstraint(item: square, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1.0, constant: 0),
])

Hi I did this thing in one of my project:
Here is a code of VC, you also need to create a custom class for your tableview cell
import UIKit
class ViewController: UIViewController {
//MARK:- view life cycle
override func viewDidLoad() {
super.viewDidLoad()
self.configureTableView()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//Custom method
func configureTableView(){
let tblview = UITableView(frame: view.bounds, style: .plain)
tblview.register(CustomTableViewCell.self, forCellReuseIdentifier: "CustomTableViewCell")
tblview.delegate = self
tblview.dataSource = self
self.view.addSubview(tblview)
}
}
extension ViewController: UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = CustomTableViewCell(style: .default, reuseIdentifier: "CustomTableViewCell")
if indexPath.row == 0 {
cell.backgroundColor = .gray
cell.lblTitle.text = "Title"
cell.lblDescription.text = "MessageMe"
return cell
}
else if indexPath.row == 1{
cell.backgroundColor = .green
cell.lblTitle.text = "TitleTitleTitleTitleTitleTitle"
cell.lblDescription.text = "MessageMe"
return cell
}
else{
cell.backgroundColor = .red
cell.lblTitle.text = "Name"
cell.lblDescription.text = "MessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessageMessag"
return cell
}
}
}
Here is code for custom class
import UIKit
class CustomTableViewCell: UITableViewCell {
//Cell View Object
let imgUser = UIImageView()
let lblTitle = UILabel()
let lblDescription = UILabel()
//constant
let paddingWithContent:CGFloat = 20.0
let gapBetweenObject:CGFloat = 10.0
let heightWidthImage:CGFloat = 40.0
let heightTitle:CGFloat = 25.0
//Init
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
//cell object property
imgUser.backgroundColor = .blue
imgUser.contentMode = .scaleAspectFill
lblDescription.numberOfLines = 0
lblTitle.adjustsFontSizeToFitWidth = true
lblTitle.minimumScaleFactor = 0.7
//translatesAutoresizingMas
imgUser.translatesAutoresizingMaskIntoConstraints = false
lblTitle.translatesAutoresizingMaskIntoConstraints = false
lblDescription.translatesAutoresizingMaskIntoConstraints = false
//add to cell
contentView.addSubview(imgUser)
contentView.addSubview(lblTitle)
contentView.addSubview(lblDescription)
//add constraint
NSLayoutConstraint.activate([
//img
imgUser.topAnchor.constraint(equalTo: contentView.topAnchor, constant: paddingWithContent),
imgUser.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: paddingWithContent),
imgUser.widthAnchor.constraint(equalToConstant: heightWidthImage),
imgUser.heightAnchor.constraint(equalToConstant: heightWidthImage),
//title lable
lblTitle.topAnchor.constraint(equalTo: contentView.topAnchor, constant: paddingWithContent),
lblTitle.leadingAnchor.constraint(equalTo: imgUser.leadingAnchor, constant: heightWidthImage + gapBetweenObject),
lblTitle.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -paddingWithContent),
lblTitle.heightAnchor.constraint(equalToConstant: heightTitle),
//description label
lblDescription.topAnchor.constraint(equalTo: lblTitle.bottomAnchor, constant: gapBetweenObject),
lblDescription.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -paddingWithContent),
lblDescription.leadingAnchor.constraint(equalTo: imgUser.leadingAnchor, constant: heightWidthImage + gapBetweenObject),
lblDescription.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -paddingWithContent),
])
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

Related

UICollectionView Not Responding to Touch

I am trying to programmatically draw my CollectionView from within a custom class that subclasses UIView. The app loads up with no errors and the CollectionView is being drawn correctly as I can see the cell items, but the CollectionView does not respond to touch. When I try to scroll nothing happens.
I inspected the ViewController using the Debug View Hierarchy button in Xcode to see if there was possibly a view on top. There was not and I could see the cells clearly drawn separately.
Class:
class DrawUI_mainCollectionView : UIView, UICollectionViewDelegate, UICollectionViewDataSource {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
var collectionView : UICollectionView?
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.addSubview(self.collectionView!)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 20
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MealCategoryCell
cell.label.text = "test"
cell.textDescription.text = "textDescription"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: kScreenWidth, height: 137)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("cell \(indexPath.row)")
}
required init?(coder aDecoder: NSCoder) {
fatalError("no storyboard...")
}
}
How I am implementing it on my ViewController
let collectionView = DrawUI_mainCollectionView()
self.view.addSubview(collectionView)
What am I doing wrong? Thanks in advance.
I think your main issue is not using auto layout, if you will add auto layout for the items:
view that contains the collectionView in viewController
collectionView in the view
It should work, the implementation:
In ViewController:
let collectionView = DrawUI_mainCollectionView()
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(collectionView)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
Inside the view:
private func setup() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: CGFloat(kScreenWidth),height: 137)
let offset = 120.0
let collectionViewFrame = CGRect(x: 0, y: offset, width: Double(kScreenWidth), height: Double(kScreenHeight))
self.collectionView = UICollectionView(frame: collectionViewFrame, collectionViewLayout: layout)
self.collectionView!.alwaysBounceVertical = true
self.collectionView!.delegate = self
self.collectionView!.dataSource = self
self.collectionView!.register(UINib(nibName: "MealCategoryCell", bundle:Bundle.main), forCellWithReuseIdentifier: "cell")
self.collectionView!.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(self.collectionView!)
NSLayoutConstraint(item: collectionView , attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leadingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailingMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .top, relatedBy: .equal, toItem: self, attribute: .topMargin, multiplier: 1.0, constant: 0.0).isActive = true
NSLayoutConstraint(item: collectionView , attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottomMargin, multiplier: 1.0, constant: 0.0).isActive = true
}

collectionView hide my custom view in header

I'm trying to add customView into headerView of my collectionView. Here's my code:
I registed the headerView class in viewDidLoad:
collectionView.register(SearchReuseView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell")
Then I setup the collectionView:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
var reuseView: UICollectionReusableView?
if indexPath.section == 0 || banners.count == 0 {
let view = UICollectionReusableView(frame: CGRect.zero)
reuseView = view
} else {
if kind == UICollectionElementKindSectionHeader {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell", for: indexPath) as! SearchReuseView
view.backgroundColor = .black
view.delegate = self
view.frame = CGRect(x: 0, y: 0, width: collectionView.frame.width, height: 100)
view.item = banners[indexPath.section % banners.count]
return view
}
}
return reuseView!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
if section == 0 {
return CGSize.zero
}
return CGSize(width: collectionView.frame.width, height: 100)
}
But when I run on Simulator, the collectionView shows the header but nothing inside.
Here is code of SearchReuseView :
class SearchReuseView: UICollectionReusableView {
weak var delegate: SearchReuseDelegate?
let adImageView: UIImageView = {
let img = UIImageView()
img.translatesAutoresizingMaskIntoConstraints = false
img.contentMode = .scaleAspectFit
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.setupViews()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setupViews()
}
func setupViews() {
backgroundColor = .black
adImageView.isUserInteractionEnabled = true
adImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.adImageView, attribute: .bottom, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: self.adImageView, attribute: .right, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.adImageView, attribute: .top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: self.adImageView, attribute: .left, multiplier: 1, constant: 0))
addSubview(adImageView)
}
var item: Banner! {
didSet {
guard let img = item.img else {return}
let url = URL(string: "\(img)")
self.adImageView.kf.setImage(with: url, placeholder: nil, options: [.transition(ImageTransition.fade(1))], progressBlock: { (receivedSize, totalSize) in
}) { (image, error, cacheType, imageURL) in
if error != nil {}
}
}
}
#objc func handleTap(){
guard let link = item.link else {
return
}
delegate?.didTapAds(link: link)
}
}
I wonder why your app is not crashing you should add subview first then add constraints to it
Replace your code with following code
func setupViews() {
backgroundColor = .black
addSubview(adImageView)
addSubview.translatesAutoresizingMaskIntoConstraints = false
adImageView.isUserInteractionEnabled = true
adImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: self.adImageView, attribute: .bottom, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .right, relatedBy: .equal, toItem: self.adImageView, attribute: .right, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: self.adImageView, attribute: .top, multiplier: 1, constant: 0))
self.addConstraint(NSLayoutConstraint(item: self, attribute: .left, relatedBy: .equal, toItem: self.adImageView, attribute: .left, multiplier: 1, constant: 0))
}
Hope it is helpful
if kind == UICollectionElementKindSectionHeader {
let view = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "reuseCell", for: indexPath) as! SearchReuseView
view.backgroundColor = .black
view.delegate = self
view.frame = CGRect(x: 0, y: 0, width: collectionView.frame.width, height: 100) //delete this line
view.item = banners[indexPath.section % banners.count]
return view
}
I delete the line set frame for header view and it's works

Add UIView to ContentView in a TableViewCell using constraints

I am trying to add cells to UITableView using Constraints. Do you know how. The following just gives:
And says: Height is ambiguous for UIView
Do you know how to add a UIView to ContextView using constraints - note the fixed height in the constraints.
import UIKit
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier:"Cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
}
let view = UIView(frame: cell!.frame)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.orange
let constraintTop = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.top,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.top,
multiplier: 1,
constant: 0)
let constraintLeading = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.leading,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.leading,
multiplier: 1,
constant: 0)
let constraintTrailing = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.trailing,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.trailing,
multiplier: 1,
constant: 0)
let constraintHeight = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.height,
relatedBy: NSLayoutRelation.equal,
toItem: nil,
attribute: NSLayoutAttribute.height,
multiplier: 1, constant: 50) // << Note fixed height
view.translatesAutoresizingMaskIntoConstraints = false
cell?.contentView.addSubview(view)
cell?.contentView.addConstraints([constraintTop, constraintLeading, constraintTrailing, constraintHeight])
return cell!
}
}
Tried to change constraints to include bottom of the contentView:
import UIKit
class ViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier:"Cell")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
}
let view = UIView(frame: cell!.frame)
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.orange
let constraintTop = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.top,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.top,
multiplier: 1,
constant: 0)
let constraintLeading = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.leading,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.leading,
multiplier: 1,
constant: 0)
let constraintTrailing = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.trailing,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.trailing,
multiplier: 1,
constant: 0)
let constraintBottom = NSLayoutConstraint(item: cell!.contentView,
attribute: NSLayoutAttribute.bottom,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.bottom,
multiplier: 1, constant: 0)
view.translatesAutoresizingMaskIntoConstraints = false
cell?.contentView.translatesAutoresizingMaskIntoConstraints = false
cell?.contentView.addSubview(view)
cell?.contentView.addConstraints([constraintTop, constraintLeading, constraintTrailing, constraintBottom])
return cell!
}
}
You're doing a couple things wrong.
First, you are setting the constraints backward. You want to constrain your new view to the contentView:
let constraintTop = NSLayoutConstraint(item: view, // constrain this view
attribute: NSLayoutAttribute.top,
relatedBy: NSLayoutRelation.equal,
toItem: cell?.contentView, // to this view
attribute: NSLayoutAttribute.top,
multiplier: 1,
constant: 0)
Second, don't do this:
cell?.contentView.translatesAutoresizingMaskIntoConstraints = false
Third, your code is (well, will be) adding a new "orange view" every time the cell is reused. Much better to add subviews in the init portion of a custom cell class, but if you're going to do it in cellForRow, check if it's already there first:
if cell.contentView.subviews.count == 0 {
// no, so add it here
let view = UIView()
// continue with view setup
Fourth, you may find it easier / more logical / cleaner / etc to add constraints this way:
cell.contentView.addSubview(view)
view.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 0.0).isActive = true
view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: 0.0).isActive = true
view.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 0.0).isActive = true
view.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: 0.0).isActive = true
And... since you have registered a cell class for reuse, this format will give you a valid cell:
// instead of this
//var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
//if cell == nil {
// cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
//}
// better method
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
So, here is the full function:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
// have we already added the subview?
if cell.contentView.subviews.count == 0 {
// no, so add it here
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = UIColor.orange
cell.contentView.addSubview(view)
view.topAnchor.constraint(equalTo: cell.contentView.topAnchor, constant: 0.0).isActive = true
view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor, constant: 0.0).isActive = true
view.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor, constant: 0.0).isActive = true
view.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor, constant: 0.0).isActive = true
}
return cell
}
Your fourth constraint is applying a fixed height to the contentView. What you want instead is to pin the bottom edges of the contentView and your custom view (like you did with leading/top/trailing) and apply the constant height constraint to view, not contentView. contentView simply adapts to its subviews, you don't tell it its height directly.
Additionally, in your viewDidLoad, you'll want to set your tableView.rowHeight = UITableViewAutomaticDimension, since you're calculating the height via constraints.
Also, you will run into problems because this code is in cellForRow. This function is called every time a new cell comes onscreen, which means as you scroll, you're going to reuse the same views and have duplicate extra views added. I recommend you subclass UITableViewCell and put this code in its init.
Well, the solutions is: Read the "Output"!
Changing the translatesAutoresizingMaskIntoConstraints property of the contentView of a UITableViewCell is not supported and will result in undefined behavior, as this property is managed by the owning UITableViewCell
Having the following messed it all up:
cell?.contentView.translatesAutoresizingMaskIntoConstraints = false
Remove this line and it will work.

Adding UITableView programmatically

I think I have looked through a lot of questions like mine but nothing seems to work.
I am sending request to the server and in the moment I get all the data, I am starting to fill my ViewController programmatically. And all this happening in main_queue
This is the code of adding table:
if self.attachments.count > 0 {
docTableView = UITableView(frame: CGRect(x: 0.0, y: 0.0, width: self.myView.frame.width, height: 500.0), style: UITableViewStyle.Plain)
docTableView!.translatesAutoresizingMaskIntoConstraints = false
docTableView!.registerNib(UINib(nibName: "MenuCell", bundle: nil), forCellReuseIdentifier: "MenuCell")
self.myView.addSubview(docTableView!)
docTableView!.dataSource = self
docTableView!.delegate = self
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
self.docTableView?.reloadData()
subviews?.append(docTableView!)
}
Then, I realized that two methods have been called : numberOfRowsInSection, heightForRowAtIndexPath and even the count of elements is greater than 0.
But cellForRowAtIndexPath is not being called and I guess that the reason that I do not see the tableView at all.
So how can I get to it?
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.docTableView {
return attachments.count
}
else {
return self.notificationViewModel!.comments.count
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100.0 // I add this to show that its not zero
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView == self.docTableView {
let object = attachments[indexPath.row]
UIApplication.sharedApplication().openURL(NSURL(string: object.Url!)!)
}
}
So commTableView is the same as docTableView. I need both of them and they have the same problem.
EDIT: I have this hierarchy: View->ScrollView->myView
EDIT2: My ViewController code. I have different types of data to add but all of it needs tables of attachments and comments
class NotificationViewController: UIViewController, MarkChosenDelegate, UITableViewDataSource, UITableViewDelegate {
//IBOutlets FROM STORYBOARD
#IBOutlet weak var myView: UIView!
#IBOutlet weak var headerStackView: UIStackView!
#IBOutlet weak var setMarkButton: UIButton!
#IBOutlet weak var placingWayCodeLabel: UILabel!
#IBOutlet weak var leftDaysLabel: UILabel!
#IBOutlet weak var typeLabel: UILabel!
#IBOutlet weak var regionLabel: UILabel!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var notificationNameLabel: UILabel!
#IBOutlet weak var markColorButton: UIButton!
var docTableView:UITableView?
var commTableView:UITableView?
var delegate:NewMarkSetProtocol?
var notificationViewModel: NotificationViewModel?
var attachments:[Attachment] = []
//FIELDS FOR SEGUE TO THE CUSTOMER
var customerGuid:String?
var customerName:String?
var inn:String?
var kpp:String?
let marks = DataClass.sharedInstance.marks
var viewUtils:ViewUtils?
var notificationItem: NotificationT? {
didSet {
self.setUpTheHeaderInformation()
}
}
//VIEW CONTROLLER LIFE CYCLES METHODS
override func viewDidLoad() {
super.viewDidLoad()
self.setUpTheHeaderInformation()
viewUtils = ViewUtils()
viewUtils?.showActivityIndicator(self.view)
notificationViewModel = NotificationViewModel()
notificationViewModel?.delegateComments = self
notificationViewModel?.delegateInformation = self
if (notificationItem != nil) {
if UsefulClass.isConnectedToNetwork() == true {
notificationViewModel!.getNotification(notificationItem!)
notificationViewModel!.getComments((notificationItem?.NotificationGuid)!)
} else {
notificationViewModel!.getCoreNotification(notificationItem!)
}
}
print(setMarkButton)
}
func setUpTheHeaderInformation() {
if let notificationT = self.notificationItem {
self.navigationItem.title = notificationT.OrderName
self.notificationItem?.IsRead = true
if let label = self.notificationNameLabel {
label.text = notificationT.OrderName
self.placingWayCodeLabel.text = notificationT.getPlacingWayId()
self.leftDaysLabel.text = notificationT.getLeft()
self.typeLabel.text = notificationT.getType()
if (marks.count != 0) {
var mark:MarkClass?
for i in 0..<marks.count {
if (marks[i].Id == notificationT.MarkId) {
mark = marks[i]
}
}
if let _mark = mark {
self.setMarkButton.setTitle(String(_mark.Name!), forState: .Normal)
self.markColorButton.hidden = false
self.markColorButton.backgroundColor = UsefulClass.colorWithHexString(_mark.Color!)
} else {
self.markColorButton.hidden = true
}
}
if let code = notificationT.RegionCode {
self.regionLabel.text = UsefulClass.regionByRegionCode(code)
}
}
}
}
//TABLE VIEW
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count:Int = 2
if tableView == self.docTableView {
print(attachments.count)
return attachments.count
}
if tableView == self.commTableView {
return self.notificationViewModel!.comments.count
}
return count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100.0
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView == self.docTableView {
let object = attachments[indexPath.row]
UIApplication.sharedApplication().openURL(NSURL(string: object.Url!)!)
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.docTableView {
let cell = tableView.dequeueReusableCellWithIdentifier("MenuCell", forIndexPath: indexPath) as! MenuCell
let object = attachments[indexPath.row]
let endIndex = object.FileName!.endIndex.advancedBy(-4)
let type:String = (object.FileName?.substringFromIndex(endIndex))!
cell.imageMark.image = notificationViewModel!.getImageForAttachment(type)
cell.name.text = object.FileName
cell.count.text = ""
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier("CommentItemCell", forIndexPath: indexPath) as! CommentTableViewCell
let object = self.notificationViewModel!.comments[indexPath.row]
if let name = object.getCreatorName() {
cell.nameUser.text = name
}
cell.textComment.text = object.Text
//cell.imageUser.image =
cell.timeComment.text = object.getTime()
return cell
}
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
if tableView == self.commTableView {
return true
} else {
return false
}
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
Requests.deleteComment(notificationViewModel!.comments[indexPath.row].Id!, notificationGuid: (self.notificationItem?.NotificationGuid)!)
notificationViewModel?.comments.removeAtIndex(indexPath.row)
self.commTableView!.reloadData()
} else {
}
}
extension String {
func heightWithConstrainedWidth(width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: CGFloat.max)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.height
}
}
extension NSAttributedString {
func heightWithConstrainedWidth(width: CGFloat) -> CGFloat {
let constraintRect = CGSize(width: width, height: CGFloat.max)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
return ceil(boundingBox.height)
}
func widthWithConstrainedHeight(height: CGFloat) -> CGFloat {
let constraintRect = CGSize(width: CGFloat.max, height: height)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, context: nil)
return ceil(boundingBox.width)
}
}
extension NotificationViewController:NotificationInformationUpdate {
func informationUpdate() {
var subviews:[UIView]? = [UIView]()
switch(notificationItem?.Type)! {
case 0:
let notification = notificationViewModel?.notification as! Notification_223
self.attachments = notification.attachments
if let name = notification.TenderPlanOrganisationName {
subviews = addTitleandValue("Заказчик", _value: name, _subviews: subviews!, numberOfLines: 0)
}
if let initialSum = notification.InitialSum {
subviews = addTitleandValue("Цена контракта", _value: initialSum, _subviews: subviews!, numberOfLines: 0)
} else if let maxPrice = notificationItem?.MaxPrice {
subviews = addTitleandValue("Цена контракта", _value: UsefulClass.getMaxPrice(maxPrice), _subviews: subviews!, numberOfLines: 0)
}
break
case 1:
let notification = notificationViewModel?.notification as! Notification_44
self.attachments = notification.attachments!
let customerNameTitle = UILabel()
customerNameTitle.text = "Заказчик:"
customerNameTitle.translatesAutoresizingMaskIntoConstraints = false
customerNameTitle.textColor = UIColor.grayColor()
setSimilarConstraintsToTitlesLabels(customerNameTitle, relatedView: self.headerStackView)
let customerName = UILabel()
customerName.text = notification.TenderPlanOrganisationName
customerName.textColor = UIColor.blueColor()
customerName.userInteractionEnabled = true
let tapGester = UITapGestureRecognizer(target: self, action: #selector(NotificationViewController.customerNameClick(_:)))
customerName.addGestureRecognizer(tapGester)
subviews = setSimilarConstraintsToValuesLabels(customerName, relatedView: customerNameTitle, _subViews: subviews!)
if let maxprice = notificationItem?.MaxPrice {
subviews = addTitleandValue("Цена контракта", _value: UsefulClass.getMaxPrice(maxprice), _subviews: subviews!, numberOfLines: 0)
}
break
case 2:
let notification = notificationViewModel?.notification as! B2BNotification
self.attachments = notification.attachments
subviews = addTitleandValue("Заказчик", _value: notification.TenderPlanOrganisationName!, _subviews: subviews!, numberOfLines: 0)
if let priceTotal = notification.PriceTotal {
var value = UsefulClass.getMaxPrice(priceTotal)
if let pricevat = notification.PriceVAT {
value.appendContentsOf(" (" + pricevat + ")")
}
subviews = addTitleandValue("Начальная цена всего лота", _value: value, _subviews: subviews!, numberOfLines: 0)
} else {
subviews = addTitleandValue("Начальная цена всего лота", _value: "Отсутствует поле", _subviews: subviews!, numberOfLines: 0)
}
if let priceone = notification.PriceOne {
subviews = addTitleandValue("Цена за единицу продукции", _value: UsefulClass.getMaxPrice(priceone), _subviews: subviews!, numberOfLines: 0)
}
break
case 7, 17:
let notification = notificationViewModel?.notification as! TakTorgNotification
self.attachments = notification.attachments
subviews = addTitleandValue("Наименование заказа", _value: notification.Subject!, _subviews: subviews!, numberOfLines: 0)
if let procNumber = notification.ProcedureProcedureNumber {
subviews = addTitleandValue("Номер закупки", _value: procNumber, _subviews: subviews!, numberOfLines: 0)
} else if let procNumber2 = notification.ProcedureProcedureNumber2 {
subviews = addTitleandValue("Номер закупки", _value: procNumber2, _subviews: subviews!, numberOfLines: 0)
}
if let startPrice = notification.StartPrice {
subviews = addTitleandValue("Начальная цена", _value: UsefulClass.getMaxPrice(startPrice), _subviews: subviews!, numberOfLines: 0)
}
if let peretorgPossible = notification.ProcedurePeretorgPossible {
subviews = addTitleandValue("Возможность проведения процедуры переторжки", _value: peretorgPossible, _subviews: subviews!, numberOfLines: 0)
}
if let negotiationPossible = notification.ProcedureNegotiationPossible {
subviews = addTitleandValue("Возможность проведения переговоров", _value: negotiationPossible, _subviews: subviews!, numberOfLines: 0)
}
//….
break
default:
break
}
let documentsTitle = UILabel()
documentsTitle.text = "Документы закупки"
documentsTitle.textColor = UIColor.blackColor()
documentsTitle.translatesAutoresizingMaskIntoConstraints = false
documentsTitle.font = documentsTitle.font.fontWithSize(18)
self.myView.addSubview(documentsTitle)
self.myView.addConstraint(NSLayoutConstraint(item: documentsTitle, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 12.0))
self.myView.addConstraint(NSLayoutConstraint(item: documentsTitle, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews?.append(documentsTitle)
if self.attachments.count > 0 {
docTableView = UITableView()
docTableView!.translatesAutoresizingMaskIntoConstraints = false
docTableView!.registerNib(UINib(nibName: "MenuCell", bundle: nil), forCellReuseIdentifier: "MenuCell")
self.myView.addSubview(docTableView!)
docTableView!.dataSource = self
docTableView!.delegate = self
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
self.myView.addConstraint(NSLayoutConstraint(item: docTableView!, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 300.0))
self.docTableView?.reloadData()
subviews?.append(docTableView!)
}
if notificationViewModel?.comments.count > 0 {
commTableView = UITableView()
commTableView?.translatesAutoresizingMaskIntoConstraints = false
commTableView!.registerNib(UINib(nibName: "CommentCell", bundle: nil), forCellReuseIdentifier: "CommentItemCell")
self.myView.addSubview(commTableView!)
self.myView.addConstraint(NSLayoutConstraint(item: commTableView!, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: commTableView!, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews?.append(commTableView!)
commTableView?.dataSource = self
commTableView?.delegate = self
}
//TITLE
let addCommentLabel = UILabel()
addCommentLabel.text = "Добавьте свой комментарий"
addCommentLabel.translatesAutoresizingMaskIntoConstraints = false
addCommentLabel.textColor = UIColor.lightGrayColor()
self.myView.addSubview(addCommentLabel)
self.myView.addConstraint(NSLayoutConstraint(item: addCommentLabel, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 10.0))
self.myView.addConstraint(NSLayoutConstraint(item: addCommentLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews?.append(addCommentLabel)
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.borderStyle = .RoundedRect
self.myView.addSubview(textField)
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Width, relatedBy: .Equal, toItem: self.myView, attribute: .Width, multiplier: 1.0, constant: -15))
subviews?.append(textField)
let sendButton = UIButton()
sendButton.setTitle("Отправить", forState: .Normal)
sendButton.translatesAutoresizingMaskIntoConstraints = false
sendButton.backgroundColor = UIColor.blueColor()
sendButton.setTitleColor(UIColor.whiteColor(), forState: .Normal)
self.myView.addSubview(sendButton)
self.myView.addConstraint(NSLayoutConstraint(item: sendButton, attribute: .Top, relatedBy: .Equal, toItem: subviews!.last, attribute: .Bottom, multiplier: 1.0, constant: 5.0))
self.myView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Trailing, relatedBy: .Equal, toItem: textField, attribute: .Trailing, multiplier: 1.0, constant: 0))
subviews?.append(sendButton)
var height:CGFloat = 0.0
for i in 0..<self.myView.subviews.count {
height = height + myView.subviews[i].bounds.height
}
self.myView.frame = CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.myView.frame.height + height)
self.view.frame = CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.view.frame.height + height)
self.scrollView.frame = CGRect(x: 0, y: 0, width: self.myView.frame.width, height: self.scrollView.frame.height + height)
self.scrollView.contentSize = CGSize(width: self.myView.frame.width, height: self.scrollView.frame.height + height)
subviews = nil
self.viewUtils?.hideActivityIndicator(self.view)
}
func addPubDate(_subviews:[UIView], date:String, number:String) -> [UIView] {
var subviews = _subviews
let pubDateLabel = UILabel()
pubDateLabel.text = "Дата публикации: " + UsefulClass.covertDataWithZ(date, withTime: false)
pubDateLabel.translatesAutoresizingMaskIntoConstraints = false
pubDateLabel.textColor = UIColor.blackColor()
pubDateLabel.font = pubDateLabel.font.fontWithSize(11)
self.myView.addSubview(pubDateLabel)
self.myView.addConstraint(NSLayoutConstraint(item: pubDateLabel, attribute: .Top, relatedBy: .Equal, toItem: subviews.last, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: pubDateLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews.append(pubDateLabel)
notificationUrlNumber(subviews, relatedView: pubDateLabel, number: number)
return subviews
}
func notificationUrlNumber(subviews:[UIView], relatedView:UILabel, number:String) {
let label = UILabel()
label.text = "Извещение №: " + number
label.textColor = UIColor.blueColor()
setSimilarConstraintsToValuesLabels(label, relatedView: relatedView, _subViews: subviews)
}
//левый заголовок для поля
func addtitle(_title:String, _subviews:[UIView]) -> [UIView] {
var subviews = _subviews
let title = UILabel()
title.text = _title
title.numberOfLines = 0
title.textColor = UIColor.blackColor()
title.translatesAutoresizingMaskIntoConstraints = false
title.font = title.font.fontWithSize(18)
self.myView.addSubview(title)
self.myView.addConstraint(NSLayoutConstraint(item: title, attribute: .Top, relatedBy: .Equal, toItem: subviews.last, attribute: .Bottom, multiplier: 1.0, constant: 12.0))
self.myView.addConstraint(NSLayoutConstraint(item: title, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
subviews.append(title)
return subviews
}
//правое значение для информационого поля
func addTitleandValue(_title:String, _value:String, _subviews:[UIView], numberOfLines:Int) -> [UIView] {
var subviews = _subviews
let title = UILabel()
title.text = _title
title.font = title.font.fontWithSize(12)
if subviews.count > 0 {
setSimilarConstraintsToTitlesLabels(title, relatedView: (subviews.last!))
} else {
setSimilarConstraintsToTitlesLabels(title, relatedView: self.headerStackView)
}
let value = UILabel()
value.text = _value
value.numberOfLines = numberOfLines
value.font = value.font.fontWithSize(12)
subviews = setSimilarConstraintsToValuesLabels(value, relatedView: title, _subViews: subviews)
return subviews
}
func addBoolEptrfValues(_title:String, _subviews:[UIView])->[UIView] {
var subviews = _subviews
let title = UILabel()
title.text = _title
title.numberOfLines = 0
setSimilarConstraintsToTitlesLabels(title, relatedView: (subviews.last!))
let value = UILabel()
value.text = notificationViewModel?.convertBoolToString(true)
value.textColor = UIColor.blackColor()
subviews = setSimilarConstraintsToValuesLabels(value, relatedView: title, _subViews: subviews)
return subviews
}
func addDeleteButton(subviews:[UIView], isDeleted:Bool) -> UILabel {
let deleteLabel = UILabel()
if isDeleted == false {
deleteLabel.text = "Удалить"
} else {
deleteLabel.text = "Восстановить"
}
deleteLabel.translatesAutoresizingMaskIntoConstraints = false
deleteLabel.textColor = UIColor.blueColor()
deleteLabel.font = deleteLabel.font.fontWithSize(11)
self.myView.addSubview(deleteLabel)
self.myView.addConstraint(NSLayoutConstraint(item: deleteLabel, attribute: .Top, relatedBy: .Equal, toItem: subviews.last, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: deleteLabel, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
return deleteLabel
}
//right values next to the title
func setSimilarConstraintsToValuesLabels(subView:UILabel, relatedView:UILabel, _subViews:[UIView]) -> [UIView] {
var subViews = _subViews
subView.translatesAutoresizingMaskIntoConstraints = false
self.myView.addSubview(subView)
if (relatedView.text?.characters.count < 35 && subView.text?.characters.count < 30) {
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Right, relatedBy: .Equal, toItem: self.myView, attribute: .Right, multiplier: 1.0, constant: -15))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Left, relatedBy: .Equal, toItem: relatedView, attribute: .Right, multiplier: 1.0, constant: 5))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .FirstBaseline, relatedBy: .Equal, toItem: relatedView, attribute: .LastBaseline, multiplier: 1.0, constant: 0))
} else {
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Top, relatedBy: .Equal, toItem: relatedView, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Width, relatedBy: .Equal, toItem: self.myView, attribute: .Width, multiplier: 1.0, constant: -15))
self.myView.addConstraint(NSLayoutConstraint(item: relatedView, attribute: .Width, relatedBy: .Equal, toItem: self.myView, attribute: .Width, multiplier: 1.0, constant: -15))
subViews.append(relatedView)
}
subViews.append(subView)
return subViews
}
func setSimilarConstraintsToTitlesLabels(subView:UILabel, relatedView:UIView) {
subView.translatesAutoresizingMaskIntoConstraints = false
subView.textColor = UIColor.grayColor()
subView.numberOfLines = 0
self.myView.addSubview(subView)
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Top, relatedBy: .Equal, toItem: relatedView, attribute: .Bottom, multiplier: 1.0, constant: 8.0))
self.myView.addConstraint(NSLayoutConstraint(item: subView, attribute: .Leading, relatedBy: .Equal, toItem: self.headerStackView, attribute: .Leading, multiplier: 1.0, constant: 0))
}
}
The method "informationUpdate()" is called when information for showing is parsed.
Your tableView has no height Constraint, so the height is set to 0.
Then no cell are visible => cellForRow never called :)
I think you should try to create more clear code. Do not use "blind" array of subviews; do not append views directly to subviews property, you already added it to view hierarchy; if you use autolayout (translatesAutoresizingMaskIntoConstraints = false) - don't try mix it with frames in single view, go and set up all constraints; use different background colors for different views to debug view hierarchy at runtime; go to Xcode Debug\View Debugging\Capture View Hierarchy for deep explore view hierarchy at runtime
Also, if numberOfRowsInSection did called by UITableView and return value > 0 (check it!), then cellForRowAtIndexPath must be called immediately by this UITableView since dataSource property is set. If you have more than one UITableView objects - check if there is no unexpected replaces.
P.S. if you from Russia I can help on Russian lang

How to properly autolayout subviews of custom tableviewcell programatically [iOS9]

I created own subclass of UITableViewCell. There are a few subviews (2x imageview, 2x UILabel). I did everything programatically also constraints but on some cells autolayout isn't computed properly and I don't know why. And here is screenshot of my tableview with mentioned issue.
Thanks for any advice.
Here is source of my cell
//menu list cell
class TableMenuViewCell: UITableViewCell{
var stripe:UIView?
var separatorTop:UIView?
var separatorBottom:UIView?
var imageBox:UIView?
var img:UIImageView?
var dateBox:UIImageView?
var date:UILabel?
var label:UILabel?
var desc:UILabel?
var foreground:UIView?
var multiplier:CGFloat = 1
var didSetupConstraints:Bool = false
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.backgroundColor = Constants.grayColor
if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad {
multiplier = 1.3
}
//stripe
stripe = UIView()
stripe!.backgroundColor = Constants.light2GrayColor
stripe!.translatesAutoresizingMaskIntoConstraints = false
addSubview(stripe!)
//image box
imageBox = UIView()
imageBox!.backgroundColor = UIColor.clearColor()
imageBox!.translatesAutoresizingMaskIntoConstraints = false
addSubview(imageBox!)
//image view
img = UIImageView()
img!.backgroundColor = UIColor.clearColor()
img!.contentMode = UIViewContentMode.ScaleAspectFill
img!.clipsToBounds = true;
img!.translatesAutoresizingMaskIntoConstraints = false
imageBox!.addSubview(img!)
//constraints
imageBox!.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[img]-0-|", options: [], metrics: nil, views: ["img" : img! ]))
imageBox!.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-0-[img]-0-|", options: [], metrics: nil, views: ["img" : img! ]))
//label
label = UILabel()
label!.numberOfLines = 0
label!.backgroundColor = UIColor.clearColor()
label!.textColor = UIColor.whiteColor()
label!.textAlignment = NSTextAlignment.Left
label!.font = UIFont(name: Constants.FONT_MEDIUM, size: Constants.MENU_LABEL_FONT_SIZE * multiplier)
label!.translatesAutoresizingMaskIntoConstraints = false
addSubview(label!)
label!.sizeToFit()
//desc
desc = UILabel()
desc!.numberOfLines = 0
desc!.backgroundColor = UIColor.clearColor()
desc!.textColor = Constants.turquoiseColor
desc!.textAlignment = NSTextAlignment.Left
desc!.font = UIFont(name: Constants.FONT_THIN, size: Constants.MENU_DESC_FONT_SIZE * multiplier)
desc!.translatesAutoresizingMaskIntoConstraints = false
addSubview(desc!)
desc!.sizeToFit()
//separator top
separatorTop = UIView()
separatorTop!.backgroundColor = Constants.lightGrayColor
separatorTop!.translatesAutoresizingMaskIntoConstraints = false
addSubview(separatorTop!)
//separator bottom
separatorBottom = UIView()
separatorBottom!.backgroundColor = Constants.lightGrayColor
separatorBottom!.translatesAutoresizingMaskIntoConstraints = false
addSubview(separatorBottom!)
//foreground
foreground = UIView()
foreground!.backgroundColor = Constants.light2GrayHoverColor
foreground!.alpha = 0.5
foreground!.opaque = false
self.selectedBackgroundView = foreground!
}
//set layout
func setLayout(rowIndex : Int){
if didSetupConstraints{
return
}
else{
didSetupConstraints = true
}
let views:[String:AnyObject] = ["stripe" : stripe!, "imageBox" : imageBox!, "label" : label!, "desc" : desc!, "separatorTop" : separatorTop!, "separatorBottom" : separatorBottom!]
let metrics:[String:AnyObject] = ["hMargin" : Constants.HORIZONTAL_MARGIN, "vMargin" : Constants.VERTICAL_MARGIN, "stripeWidth" : Constants.STRIPE_WIDTH, "separatorHeight" : Constants.SEPARATOR_HEIGHT]
var constraintsArr:[NSLayoutConstraint] = []
//horizontal constraints
constraintsArr.appendContentsOf( NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[separatorTop]-0-|", options: [], metrics: metrics, views: views) )
constraintsArr.appendContentsOf( NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[separatorBottom]-0-|", options: [], metrics: metrics, views: views) )
constraintsArr.appendContentsOf( NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[stripe(==stripeWidth)]-(hMargin)-[imageBox]-(hMargin)-[label]-0-|", options: [], metrics: metrics, views: views) )
constraintsArr.appendContentsOf( NSLayoutConstraint.constraintsWithVisualFormat("H:|-0-[stripe(==stripeWidth)]-(hMargin)-[imageBox]-(hMargin)-[desc]-0-|", options: [], metrics: metrics, views: views) )
constraintsArr.append(NSLayoutConstraint(item: imageBox!, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.height - 4*Constants.VERTICAL_MARGIN))
//vertical constraints
constraintsArr.append(NSLayoutConstraint(item: stripe!, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.height))
constraintsArr.append(NSLayoutConstraint(item: stripe!, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: separatorTop!, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0))
constraintsArr.append(NSLayoutConstraint(item: stripe!, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: separatorBottom!, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: 0))
constraintsArr.append(NSLayoutConstraint(item: imageBox!, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
constraintsArr.append(NSLayoutConstraint(item: imageBox!, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.height - 4*Constants.VERTICAL_MARGIN))
if desc!.text!.isEmpty {
constraintsArr.append(NSLayoutConstraint(item: label!, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0))
}else{
constraintsArr.append(NSLayoutConstraint(item: label!, attribute: NSLayoutAttribute.CenterYWithinMargins, relatedBy: NSLayoutRelation.Equal, toItem: self, attribute: NSLayoutAttribute.CenterYWithinMargins, multiplier: 1, constant: -label!.bounds.height*0.5))
constraintsArr.append(NSLayoutConstraint(item: desc!, attribute: NSLayoutAttribute.TopMargin, relatedBy: NSLayoutRelation.Equal, toItem: label!, attribute: NSLayoutAttribute.Bottom, multiplier: 1, constant: Constants.VERTICAL_MARGIN + Constants.VERTICAL_MARGIN * multiplier ))
}
constraintsArr.append(NSLayoutConstraint(item: separatorTop!, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: rowIndex != 0 ? 0 : Constants.SEPARATOR_HEIGHT))
constraintsArr.append(NSLayoutConstraint(item: separatorBottom!, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: Constants.SEPARATOR_HEIGHT))
self.addConstraints(constraintsArr)
}
override func prepareForReuse() {
super.prepareForReuse()
imageView!.image = nil
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Source of Table view controller
import UIKit
class MenuViewController: UITableViewController {
var cellHeight:CGFloat = 50
override func viewDidLoad() {
super.viewDidLoad()
initTableView()
}
override func viewDidAppear(animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
func initTableView(){
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
tableView.backgroundColor = Constants.grayColor
tableView.delegate = self
tableView.dataSource = self
tableView.estimatedRowHeight = cellHeight
tableView.rowHeight = UITableViewAutomaticDimension
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.registerClass(TableMenuViewCell.self, forCellReuseIdentifier: NSStringFromClass(TableMenuViewCell))
}
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0.001
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad {
return cellHeight * 1.2
}
return cellHeight
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 16
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier( NSStringFromClass(TableMenuViewCell), forIndexPath: indexPath) as! TableMenuViewCell
//stripe
cell.stripe!.backgroundColor = Constants.turquoiseColor
//image
cell.img!.image = UIImage(named: "placeholder")
cell.img!.sizeToFit()
//image box
cell.imageBox!.sizeToFit()
//label
cell.label!.text = "Main Label"
cell.label!.sizeToFit()
//desc
cell.desc!.text = "Description Text"
cell.desc!.sizeToFit()
cell.setLayout(indexPath.row)
cell.setNeedsLayout()
cell.layoutIfNeeded()
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Resources