Dynamic tableView Cell height swift IOS8 - ios

I'm trying to create tableView which is suppose to auto resize the height according to the messageLabel. IOS8 has made this a lot of easier, however i can't seem to achieve this. So far i've created tableViewCell custom class with a xib file looking like below:
and then set the messageLabel.numberOfLines = 0
in the viewController i've set following in viewDidLoad
tableView.estimatedRowHeight = 80.0
tableView.rowHeight = UITableViewAutomaticDimension
and in the end the delegate methods
func tableView(tableView:UITableView, numberOfRowsInSection section:Int)->Int
{
return 1
}
func numberOfSectionsInTableView(tableView:UITableView)->Int
{
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
var cell = tableView.dequeueReusableCellWithIdentifier("TwitterPlainCell", forIndexPath: indexPath) as! TwitterPlainCell
let url = NSURL(string: "https://pbs.twimg.com/profile_images/507493048062713856/KaWKfdgW.jpeg")
let data = NSData(contentsOfURL: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check
cell.selectionStyle = UITableViewCellSelectionStyle.None
// cell.backgroundColor = UIColor(rgba: "#f6f7f9")
var name = "Olof Kajbjer"
var userName = "#olofmCS"
var topText = "\(name) \(userName)"
var topCount = count(topText)
var userCount = count(userName)
var userNameLocation = topCount - userCount
cell.profileImage.image = UIImage(data: data!)
cell.dateLabel.text = "55m"
var myMutableString = NSMutableAttributedString(string: topText, attributes: [NSFontAttributeName:UIFont(name: "PT Sans", size: 18.0)!])
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor(rgba: "#A6B0B5"), range: NSRange(location:userNameLocation,length:count(userName)))
myMutableString.addAttribute(NSFontAttributeName, value: UIFont(name: "PT Sans", size: 13)!, range: NSRange(location:userNameLocation,length:count(userName)))
// set label Attribute
cell.topLabel.attributedText = myMutableString
cell.messageLabel.text = "I FUCKING LOST AGAINST #olofmCS ON AIM AWP IN OVERTIME... GGgg"
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
return cell
}
The result of this can seen below, why is it not resizing the cell height?

The issue was related to the bottom constraint i had to set it to >= or another value

Related

Bug with UITextField inside UITableViewCell

I have a problem with some TextField inside a UITableViewCell; i got two textfield inside of the table cell, when I tap on the the textField everything works fine as you can see in this two screenshots
1.
The number in red squares are my UITextField, when I tap on one of them it works fine
But when i click on the other textField the entire cell disappear like this
I have an empty space after the click on the other textfield
I have no function implemented, only a function that change font and textColor
func setPickers() {
self.hourPicker.delegate = self
self.minutePicker.delegate = self
hourPicker.textColor = theme.grey
minutePicker.textColor = theme.grey
hourPicker.background = UIImage()
minutePicker.background = UIImage()
hourPicker.textAlignment = .center
minutePicker.textAlignment = .center
hourPicker.font = UIFont(name: "Roboto-Regular", size: 48)
minutePicker.font = UIFont(name: "Roboto-Regular", size: 48)
}
This the cell in my storyboard
EDIT 2
Look my graphic debug what shows before the bug
And after it
The cell is called EventDetailFooterTableViewCell
EDIT 3
Here is where I initialize the cellView for the footer
func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "footerCell") as! EventDetailFooterTableViewCell
cell.event = self.event
cell.delegate = self
cell.setView()
cell.backgroundColor = theme.mainColor
return cell
}
func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
var height: CGFloat = 180.0
var calendar = NSCalendar.current
calendar.timeZone = TimeZone(abbreviation: "UTC")! //OR NSTimeZone.localTimeZone()
let dateAtMidnight = calendar.startOfDay(for: Date())
let todayLong = dateAtMidnight.millisecondsSince1970
if let eventDay = event.dateTime?.millisecondsSince1970 {
if eventDay >= todayLong {
height = 280
}
}
return height
}
I see a problem. You are using regular cell as section footer and there is why you see unpredictable behaviour. You should use UITableViewHeaderFooterView instead. It is if you really need such design. Better solution will be to remove footer and make it cell instead.

UITableView Custom Cell Overlapping in ios10 with Swift3

I am making UITableView custom cell because height also changed per cell.
This is my code for initialize cell and after that i want to add UITextView as Subview.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
let dictAd = self.arrAllQuestions[indexPath.row] as! NSDictionary
let fontNew = UIFont(name: "AvenirNext-Regular", size: 19.0)
let strA = "\(indexPath.row+1). \(dictAd.object(forKey: "Title")!)"
let heightTitle = self.heightForView(text: strA, font: fontNew!, width: tableView.frame.size.width-16)
return heightTitle+5;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let dictAd = self.arrAllQuestions[indexPath.row] as! NSDictionary
let cell = tableView.dequeueReusableCell(withIdentifier: "quesionCell", for: indexPath) as! QuestionCell
let fontNew = UIFont(name: "AvenirNext-Regular", size: 19.0)
let strA = "\(indexPath.row+1). \(dictAd.object(forKey: "Title")!)"
cell.lblName.font = fontNew
cell.lblName.text = strA
cell.lblName.numberOfLines = 0
let heightTitle = self.heightForView(text: strA, font: fontNew!, width: tableView.frame.size.width-16)
var frame = cell.lblName.frame as CGRect
frame.size.height = heightTitle; //you need to adjust this value
cell.lblName.frame = frame;
let txtView = AnimatableTextView(frame: CGRect(x: 8, y: cell.lblName.frame.origin.y+cell.lblName.frame.size.height+5, width: tableView.frame.size.width-16, height: 25))
txtView.borderWidth = 1.0
txtView.borderColor = UIColor.lightGray
txtView.cornerRadius = 4.0
cell.contentView.addSubview(txtView)
return cell
}
You can see output below.
It seems that the height calculation in your heightForRowAtIndexPath is not proper. Consider using self-sizing cells using UITableViewAutomaticDimension and Autolayout to solve your issues. Here is a great tutorial that can help you to get started. One more suggestion if you are using UITextView or subclass of the same in a cell and you want it to take the height of the content set its scrollable property to false.
Declare this in the viewDidLoad
Hope this will help you
tableView.estimatedRowHeight = 44

sizeToFit() not working properly with attributedText

Here is my cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//cell init
//set values to cell property
let str2 = NSString(format: "%#", (displayArray[indexPath.row].valueForKey("username") as? String)!)
let attrStr2 = NSMutableAttributedString(string: str2 as String)
attrStr2.addAttribute(NSFontAttributeName, value:UIFont(name: "HelveticaNeue-Bold", size: 12)!, range: NSMakeRange(0, str2.length ))
topCell.username.attributedText = attrStr2
topCell.username.sizeToFit()
topCell.title.backgroundColor = UIColor.redColor()
topCell.username.backgroundColor = UIColor.yellowColor()
//some calculation which is not affecting username.frame.size.width
return topCell;
}
and here is my tableView
You can see label with yellow background,
And yes, autolayout is disable, so I think my code is fine but not working as expected.
Please help me to solve this issue.
Thanks in advance

UITableViewCell not removed from the UITableView when using reloaddata

I'm using a tableview to display some categories in a left menu. When you select it, the data in the cells changes to courses ('Cursussen') within that category.
Each cell contains an UIImageView and an UILabel.
I noticed a while ago that when you select a course in the left menu, the label will change to that of a category. That wasn't a big issue back then, but now that I'm working to disable certain courses if they are not available it suddenly became a big issue. To indicate a course that's not available, I'm setting label.enabled = false, which works fine, however I also need to prevent the user from tapping on it and navigating to a course that's not available. To do that, I'm using tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) where I check whether the UILabel is enabled. If it's disabled the App won't navigate to the course.
Back to the issue, tapping on a course that is unavailable (which is displaying the correct image and label) will trigger the didSelectRowAtIndexPath delegate, but when I dequeue the Cell and check whether the UILabel in it is disabled it so happens to be enabled instead and furthermore the label.text does not equal the value I see in the App.
State before selecting a row:
State after selecting a row:
cellForRowAtIndexPath method:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("LeftCell", forIndexPath: indexPath)
let label = cell.contentView.subviews[0] as! UILabel
let image = cell.contentView.subviews[1] as! UIImageView
if(selectedCategory.ID > 0 || searchCursusses.count > 0) {
//Category is selected, load course into cell
var cursus : Cursus
if(selectedCategory.ID > 0) {
cursus = cursusses[indexPath.row] as Cursus
} else {
cursus = searchCursusses[indexPath.row] as Cursus
}
image.image = self.chooseImage(false, name: cursus.category!.Name)
label.numberOfLines = 0
label.text = cursus.name
label.lineBreakMode = .ByTruncatingTail
if(defaults.boolForKey("offline-mode")) {
let realm = try! Realm()
let videos = realm.objects(DownloadedVideo).filter("video.cursus.ID = %#", cursus.ID)
if(videos.count > 0) {
label.enabled = true
} else {
label.enabled = false
}
} else {
label.textColor = UIColor.blackColor()
}
cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
cell.setSelected(false, animated: false)
} else {
let category = categories[indexPath.row] as Category
image.image = self.chooseImage(false, name: category.Name)
label.numberOfLines = 0
label.text = category.Name
label.lineBreakMode = .ByTruncatingTail
label.textColor = UIColor.blackColor()
cell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
}
return cell
}
didSelectRowAtIndexPath method:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier( "LeftCell", forIndexPath: indexPath)
cell.selectionStyle = .None
if(selectedCategory.ID > 0 || searchCursusses.count > 0) {
let label = cell.contentView.subviews[0] as! UILabel
if(!label.enabled) {
return
}
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let resultViewController = storyBoard.instantiateViewControllerWithIdentifier("CursusView") as! CursusViewController
if(selectedCategory.ID > 0) {
resultViewController.loadCursus(self.cursusses[indexPath.row], completionHandler: {
self.presentViewController(resultViewController, animated:true, completion:nil)
})
} else {
resultViewController.loadCursus(self.searchCursusses[indexPath.row], completionHandler: {
self.presentViewController(resultViewController, animated:true, completion:nil)
})
}
} else {
let category = categories[indexPath.row] as Category
cell.setSelected(true, animated: false)
let label = cell.contentView.subviews[0] as! UILabel
let image = cell.contentView.subviews[1] as! UIImageView
if(label.textColor == UIColor.lightGrayColor()) {
return
} else {
image.image = self.chooseImage(true, name: category.Name)
label.numberOfLines = 0
label.text = category.Name
label.textColor = UIColor.whiteColor()
label.lineBreakMode = .ByTruncatingTail
cell.backgroundColor = UIColor(red: 45.0/255.0, green: 145.0/255.0, blue: 220.0/255.0, alpha: 1.0)
self.selectedCategory = category
self.topBarTitle.text = category.Name
let realm = try! Realm()
let cursusses = realm.objects(Cursus).filter("category.ID = %#", selectedCategory.ID)
for cursus in cursusses {
self.cursusses.append(cursus)
}
let title = self.leftMenuNav.subviews[0] as! UILabel
let titleImg = self.leftMenuNav.subviews[1] as! UIImageView
titleImg.image = UIImage(named: "back-icon")
title.text = "Cursussen"
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.slideInFromRight(0.5)
self.tableView.reloadData()
self.collectionView.crossFade(0.3)
self.collectionView.reloadData()
})
}
}
}
It seems the old cells are not properly cleaned up after calling reloaddata, causing multiple cells to be at the same IndexPath.
I'm at a loss here, please help!
The problem is the line
let cell = tableView.dequeueReusableCellWithIdentifier( "LeftCell", forIndexPath: indexPath)
in the didSelectRowAtIndexPath function because it is creating a new cell (or trying to reuse one) and corrupting the table view cell cache.
You should be getting the existing cell instead using the cellForRowAtIndexPath function.
You have a problem with your approach: didSelectRowAtIndexPath is supposed to look at the data in the model, not in the view. Your code is trying, incorrectly, to access the cell and examine its labels etc. Instead, your method should be accessing the same underlying data source that has been used to make the labels in the first place.
In other words, instead of writing
let label = cell.contentView.subviews[0] as! UILabel
and then examining the enabled/disabled status of the label
you should write
cursus = cursusses[indexPath.row] as Cursus
and examine the availability of the cursus.
One general rule of thumb is that you should get very suspicious when you see code accessing components of UITableViewCell outside cellForRowAtIndexPath. Testing the state of a label is nearly universally an indication that the code is incorrect.
Man you are doing that wrong. Only tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell can dequeue cells and setup its contents.
To prevent selection you should react on func tableView(_ tableView: UITableView,
willSelectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath and return nil to indicate that you don't want to select anything.
Main problem is that you are writing to complex methods. It is hard to figure out what are you doing and what is you intention. (will/did)SelectRowAtIndexPath should invoke only one/tow some simple methods, for example: perform a segue or load some data.

Can't add circular mask in tableView

I am creating a UITableViewCell object and returning it inside cellForRowAtIndexPath function in tableView. I have a UIView in the cell which I want to make circular. Using the code from this link, I had written following code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let containerDP = UIView()
containerDP.backgroundColor = UIColor.redColor()
// some code
let firstLetter = UILabel()
firstLetter.backgroundColor = UIColor.yellowColor()
firstLetter.text = (data[indexPath.row].UserObject.FirstName! as String).uppercaseString[0]
firstLetter.font = UIFont(name: firstLetter.font.fontName, size: 50)
firstLetter.adjustsFontSizeToFitWidth = true
firstLetter.textAlignment = NSTextAlignment.Center
firstLetter.layer.cornerRadius = firstLetter.frame.size.width / 2;
firstLetter.clipsToBounds = true
containerDP.addSubview(firstLetter)
firstLetter.snp_makeConstraints { (make) -> Void in
make.center.equalTo(containerDP)
make.edges.equalTo(containerDP).inset(UIEdgeInsetsMake(10, 10, 10, 10))
}
// some code
return cell
}
But there is still no circular mask:
Try this :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = UITableViewCell()
let containerDP = UIView()
containerDP.backgroundColor = UIColor.redColor()
// some code
let firstLetter = UILabel()
firstLetter.backgroundColor = UIColor.yellowColor()
firstLetter.text = (data[indexPath.row].UserObject.FirstName! as String).uppercaseString[0]
firstLetter.font = UIFont(name: firstLetter.font.fontName, size: 50)
firstLetter.adjustsFontSizeToFitWidth = true
firstLetter.textAlignment = NSTextAlignment.Center
firstLetter.layer.cornerRadius = firstLetter.frame.size.width / 2;
firstLetter.layer.masksToBounds = true
firstLetter.clipsToBounds = true
containerDP.addSubview(firstLetter)
firstLetter.snp_makeConstraints { (make) -> Void in
make.center.equalTo(containerDP)
make.edges.equalTo(containerDP).inset(UIEdgeInsetsMake(10, 10, 10, 10))
}
// some code
return cell
}
Use dequeueReusableCellWithIdentifier for tablewView cell creating and caching
Make subview setups for tableViewCell in awakeFromNib method
With clipsToBounds = true it should work
first you should create a customtableviewCell class for your tableview.
then make IBOutlet connection to your cutomtablviewCell
then #import your customtablviewCell to your tableviewController
then inside the cellForRowAtIndexPath method(I'm well in objectiveC, not in swift) call to your cutomTableviewcell like below
customTableviewCell *cell = [your code here];
after that do your styles like
cell.fisrtLetter.layer.cornerRadius = cell.firstletter.frame.size.width/2;
cell.firstLetter.layer.masksToBounds = true;
please get the idea.

Resources