I am trying to do tableview with different cell styles. My first row's image is the largest one and has three labels. I need to set such constraints only for the first cell. The second, third, fourth rows have smaller image and the same quantity of labels. Other cells have only only labels with no image. So far I have this code:
class MainPageTableViewCell: UITableViewCell {
#IBOutlet var labelDateOfPublication: UILabel!
#IBOutlet var labelTitle: UILabel!
#IBOutlet var labelIntroText: UILabel!
#IBOutlet var imageMainPage: UIImageView!
#IBOutlet var contentViewMainCell: UIView!
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
super.init(style: UITableViewCellStyle.Value1, reuseIdentifier: reuseIdentifier)
imageMainPage.setTranslatesAutoresizingMaskIntoConstraints(false)
contentView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.setTranslatesAutoresizingMaskIntoConstraints(false)
var constX = NSLayoutConstraint(item: imageMainPage, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant: 0)
imageMainPage.addConstraint(constX)
var constY = NSLayoutConstraint(item: imageMainPage, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant: 0)
imageMainPage.addConstraint(constY)
var constW = NSLayoutConstraint(item: imageMainPage, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 300)
imageMainPage.addConstraint(constW)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I am using this main cell here:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("mainPage", forIndexPath: indexPath) as MainPageTableViewCell
println(indexPath.row)
cell.labelTitle.text = arrayMainPage[indexPath.row].pageTitle
cell.labelIntroText.text = arrayMainPage[indexPath.row].introText
cell.labelDateOfPublication.text = arrayMainPage[indexPath.row].pubDate
var link = arrayMainPage[indexPath.row].linkToImage as String
var imgCache = arrayMainPage[indexPath.row].imageDictionary
//var imgCache = imageDictionary
//println("print image aluew \(img?.)")
if let img = imgCache[link] {
let image = CommonFunctions.vignettePhoto(img, imageViewLocal:cell.imageMainPage)
// cell.image.image = image
println("it is not blank. index of array \(indexPath.row)")
}else{
CommonFunctions.loadImageAsync(link, imageView: cell.imageMainPage!, article: arrayMainPage[indexPath.row], viewContr: self)
println("it is blank index of array \(indexPath.row)")
}
return cell
}
However, the constrains that I am adding are not working. I am planning to create three UITableViewCells with different constraints. Somehow I need to programatically set cell identity to the cell that I am using. Please , somebody tell me why my constraints are not working?
Related
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)
}
}
I'm having a problem when I want to add a target to a button from a loaded xib.
I have this:
var cleanFilters = FilterLabelView()
override func viewWillAppear(_ animated: Bool) {
navigationItem.title = "EXPLORE WORKOUTS"
self.navigationController!.navigationBar.titleTextAttributes = [NSFontAttributeName: UIFont(name: "OpenSans-CondensedBold", size: 16.0)!]
setFilterLabel()
}
func setFilterLabel() {
cleanFilters = (Bundle.main.loadNibNamed("FilterLabelView", owner: self, options: nil)?.first as? FilterLabelView)!
self.view.addSubview(cleanFilters)
cleanFilters.translatesAutoresizingMaskIntoConstraints = false
self.view.addConstraint(NSLayoutConstraint(item: cleanFilters, attribute: .top, relatedBy: .equal, toItem: self.topLayoutGuide, attribute: .bottom, multiplier: 1, constant: 30))
self.view.addConstraint(NSLayoutConstraint(item: cleanFilters, attribute: .trailingMargin, relatedBy: .equal, toItem: self.view, attribute: .trailingMargin, multiplier: 1, constant: 35))
cleanFilters.deleteButton.addTarget(self, action: #selector(hideFilterLabel), for: .touchUpInside)
cleanFilters.confirmButton.addTarget(self, action: #selector(setDefaultFilters), for: .touchUpInside)
cleanFilters.isHidden = defaultsManager.isDefaultFilters()
if !cleanFilters.isHidden {
self.workoutsCollection.isUserInteractionEnabled = false
}
}
func hideFilterLabel() {
cleanFilters.isHidden = true
self.workoutsCollection.isUserInteractionEnabled = true
}
func setDefaultFilters() {
defaultsManager.setDefaultFilters()
cleanFilters.isHidden = true
getAllWorkouts()
}
The deleteButton and confirmButton actions are not being called and I can't figure out why.
Here's the FilterLabelView I'm loading:
import UIKit
class FilterLabelView: UIView {
#IBOutlet weak var deleteButton: UIButton!
#IBOutlet weak var confirmButton: UIButton!
#IBOutlet weak var labelTapRecongnizer: UITapGestureRecognizer!
}
Are you sure that your buttons are not hidden? remember that if a button is hidden the hittest can't perform touches... is it also posible your buttons are really little or have isUserInteractionEnabled as false... A good way to be aware whether is a problem with the view is looking out the Debug view hierarchy
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.
Since the upgrade to iOS 9, code that has been working fine before started to show really bad performance on scrolling.
I tried to create a minimal example from scratch leaving out most of the cell's configuration and various caching and content-generating code. Yet, the code is still not a quick read and the profiling is showing up differently :/
According to Apple Developer Forums (Edit: I found the link) this might result from how auto layout changed and having the layout heavy views in the back of it's superView made it less bad, still not good enough for release.
My suspicion is that the problem lies within UIKit, especially in auto layout and UITextView as the scrolling got instantly chunky as soon as I began setting cell.textView.text.
Has anybody made similar observations? This didn't quite seem to come up as a problem for many.
Any suggestions to make this more smooth? Using UILabels fixes it, but there are to be links in attributed strings in real life that are to be tapable, so I see no way to avoid UITextView.
I'm using custom UITableViewCell subclasses, which I simplified as well, yet they are still quite a read because of the programmatic autolayout:
class AbstractRegularTimelineCell: UITableViewCell {
weak var iconView : UIImageView!
weak var headerLabel : UILabel!
weak var timeLabel : UILabel!
weak var regularContentContainer : UIView!
weak var contentHeightConstraint : NSLayoutConstraint!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
private func commonInit() {
self.selectionStyle = .None
// add the UI elements needed for all regular cells.
let iv = UIImageView(/*image: UIImage(named: "icon")*/)
iv.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(iv)
self.iconView = iv
iv.setContentCompressionResistancePriority(1000, forAxis: .Horizontal)
iv.setContentCompressionResistancePriority(1000, forAxis: .Vertical)
let hl = UILabel()
hl.numberOfLines = 0
hl.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(hl)
self.headerLabel = hl
hl.font = UIFont(name: "OpenSans-Semibold", size: UIFont.systemFontSize())
let tiv = UIImageView(/*image: UIImage(named: "timestamp")*/)
tiv.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(tiv)
let tl = UILabel()
tl.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(tl)
self.timeLabel = tl
tl.textColor = UIColor.lightGrayColor()
tl.font = UIFont(name: "OpenSans", size: UIFont.systemFontSize()-3)
let rcc = UIView()
rcc.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(rcc)
self.regularContentContainer = rcc
rcc.setContentCompressionResistancePriority(1000, forAxis: .Vertical)
rcc.setContentCompressionResistancePriority(100, forAxis: .Horizontal)
self.contentView.sendSubviewToBack(rcc) // this might help, according to Apple Dev Forums
// now, stitch the constraints together.
let views = ["iv":iv, "hl":hl, "tl":tl, "rcc":rcc, "tiv":tiv]
self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-(15)-[iv]-(15)-[hl]-(>=15)-|", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: [:], views: views))
self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(15)-[iv]", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: nil, views: views))
self.contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-(17)-[hl]-(8)-[rcc]", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: nil, views: views))
var otherConstraints = [NSLayoutConstraint]()
var c = NSLayoutConstraint(item: tiv, attribute: .Top, relatedBy: .Equal, toItem: rcc, attribute: .Bottom, multiplier: 1, constant: 8)
c.priority = 600
otherConstraints.append(c)
c = NSLayoutConstraint(item: tiv, attribute: .Top, relatedBy: .GreaterThanOrEqual, toItem: rcc, attribute: .Bottom, multiplier: 1, constant: 6)
otherConstraints.append(c)
c = NSLayoutConstraint(item: tl, attribute: .Leading, relatedBy: .Equal, toItem: tiv, attribute: .Trailing, multiplier: 1, constant: 6)
otherConstraints.append(c)
c = NSLayoutConstraint(item: tiv, attribute: .CenterY, relatedBy: .Equal, toItem: tl, attribute: .CenterY, multiplier: 1, constant: 1)
otherConstraints.append(c)
c = NSLayoutConstraint(item: self.contentView, attribute: .Bottom, relatedBy: .Equal, toItem: tiv, attribute: .Bottom, multiplier: 1, constant: 10)
otherConstraints.append(c)
c = NSLayoutConstraint(item: tiv, attribute: .Leading, relatedBy: .Equal, toItem: hl, attribute: .Leading, multiplier: 1, constant: 0)
otherConstraints.append(c)
c = NSLayoutConstraint(item: rcc, attribute: NSLayoutAttribute.Height, relatedBy: .LessThanOrEqual, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: 10000)
otherConstraints.append(c)
self.contentHeightConstraint = c
c = NSLayoutConstraint(item: self.contentView, attribute: .Trailing, relatedBy: .GreaterThanOrEqual, toItem: rcc, attribute: .Trailing, multiplier: 1, constant: 15)
otherConstraints.append(c)
c = NSLayoutConstraint(item: rcc, attribute: .Leading, relatedBy: .Equal, toItem: hl, attribute: .Leading, multiplier: 1, constant: 0)
otherConstraints.append(c)
self.contentView.addConstraints(otherConstraints)
}
}
class ExampleCell: AbstractRegularTimelineCell {
weak var textView : UITextView!
override required init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.setupTextView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupTextView()
}
private func setupTextView() {
let t = UITextView()
t.translatesAutoresizingMaskIntoConstraints = false
self.regularContentContainer.addSubview(t)
self.regularContentContainer.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[t]|", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: [:], views: ["t":t]))
self.regularContentContainer.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[t]|", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: [:], views: ["t":t]))
self.textView = t
t.scrollEnabled = false
}
}
The less lengthy View Controller code:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
weak var tableView : UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let t = UITableView()
t.registerClass(ExampleCell.classForCoder(), forCellReuseIdentifier: "example")
t.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(t)
self.tableView = t
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[t]|", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: [:], views: ["t":t]))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[t]|", options: NSLayoutFormatOptions.DirectionLeadingToTrailing, metrics: [:], views: ["t":t]))
t.delegate = self
t.dataSource = self
t.estimatedRowHeight = 350
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 300
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : ExampleCell = tableView.dequeueReusableCellWithIdentifier("example", forIndexPath: indexPath) as! ExampleCell
cell.timeLabel.text = "probably never"
switch indexPath.row % 3 {
case 0:
cell.headerLabel.text = "First paragraph (Part one of two)"
cell.textView.text = "As any dedicated reader can clearly see, the Ideal of practical reason is a representation of, as far as I know, the things in themselves; as I have shown elsewhere, the phenomena should only be used as a canon for our understanding. These paralogisms of practical reason are what first give rise to the architectonic of practical reason."
case 1:
cell.headerLabel.text = "First paragraph, 2/2"
cell.textView.text = "As will easily be shown in the next section, reason would thereby be made to contradict, in view of these considerations, the Ideal of practical reason, yet the manifold depends on the phenomena. Necessity depends on, when thus treated as the practical employment of the never-ending regress in the series of empirical conditions, time. Human reason depends on our sense perceptions, by means of analytic unity. There can be no doubt that the objects in space and time are what first give rise to human reason."
default:
cell.headerLabel.text = "Second paragraph"
cell.textView.text = "Let us suppose that the noumena have nothing to do with necessity, since knowledge of the Categories is a posteriori. Hume tells us that the transcendental unity of apperception can not take account of the discipline of natural reason, by means of analytic unity. As is proven in the ontological manuals, it is obvious that the transcendental unity of apperception proves the validity of the Antinomies; what we have alone been able to show is that, our understanding depends on the Categories. It remains a mystery why the Ideal stands in need of reason. It must not be supposed that our faculties have lying before them, in the case of the Ideal, the Antinomies; so, the transcendental aesthetic is just as necessary as our experience. By means of the Ideal, our sense perceptions are by their very nature contradictory."
}
return cell
}
}
As #A-Live has pointed out in the comments, the problem lay in the nested scroll views.
To make this question useful to anyone, I ended up replacing the UITextViews with TTTAttributedLabels which improved performance significantly.
Also, it could not be figured out why the performance dropped as significantly with the iOS 9 update; I suspect an undocumented change to the autolayout engine; with a good workaround present, there is no need to investigate that further.
I am working on a feeds page using a UITableView, and I am trying to set a dynamic height fro the cells (to adapt according to the content.)
I have created a custom class for the cells, here's the code:
class cellTableViewCell: UITableViewCell, UINavigationControllerDelegate {
//OUTLETS
#IBOutlet weak var usernameLbl: UILabel!
#IBOutlet var profileImg: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
usernameLbl.text = "Username"
usernameLbl.textColor = UIColor.grayColor()
profileImg.layer.cornerRadius = profileImg.frame.size.width/2
profileImg.layer.masksToBounds = true
profileImg.addConstraint(NSLayoutConstraint(item: profileImg, attribute: NSLayoutAttribute.Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1.0, constant: 100.0))
contentView.addSubview(profileImg)
contentView.addConstraint(NSLayoutConstraint(item: profileImg, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: contentView, attribute: NSLayoutAttribute.Top, multiplier: 1.0, constant: 100.0))
}
And then, in the ViewDidLoad() method of the View Controller that controls the table view, I added the following:
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 160.0
However, the cells are not adapting at all since the height is still smaller than the content.
I think your Constraint is complete correct but the problem is that you can't build a UITableView with dynamic TableViewCells with different heights for every cell. I tried that myself but in a dynamic UITableViewCell the attribute rowHeight of the tableView (tableView.rowHeight). So this rowHeight will override each different height of your cells which are defined by your Constraints.
I found an answer for the problem:
You can use the function 'heightForRowAtIndexPath' of the UITableViewDelegate like this:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return CGFloat(100)
}