I am trying to set the height of each row in the tableView to the height of the corresponding cell with this code:
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
var cell = tableView.cellForRowAtIndexPath(indexPath)
return cell.frame.height
}
I get this error when initialising var cell :
Thread 1:EXC_BAD_ACCESS(code=2,address=0x306d2c)
For setting row height there is separate method:
For Swift 3
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100.0;//Choose your custom row height
}
Older Swift uses
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 100.0;//Choose your custom row height
}
Otherwise you can set row height using:
self.tableView.rowHeight = 44.0
In ViewDidLoad.
Put the default rowHeight in viewDidLoad or awakeFromNib. As pointed out by Martin R., you cannot call cellForRowAtIndexPath from heightForRowAtIndexPath
self.tableView.rowHeight = 44.0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var height:CGFloat = CGFloat()
if indexPath.row == 1 {
height = 150
}
else {
height = 50
}
return height
}
yourTableView.rowHeight = UITableViewAutomaticDimension
Try this.
As pointed out in comments, you cannot call cellForRowAtIndexPath inside heightForRowAtIndexPath.
What you can do is creating a template cell used to populate with your data and then compute its height.
This cell doesn't participate to the table rendering, and it can be reused to calculate the height of each table cell.
Briefly, it consists of configuring the template cell with the data you want to display, make it resize accordingly to the content, and then read its height.
I have taken this code from a project I am working on - unfortunately it's in Objective C, I don't think you will have problems translating to swift
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
static PostCommentCell *sizingCell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sizingCell = [self.tblComments dequeueReusableCellWithIdentifier:POST_COMMENT_CELL_IDENTIFIER];
});
sizingCell.comment = self.comments[indexPath.row];
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
return size.height;
}
Problem Cause:
The problem is that the cell has not been created yet. TableView first calculates the height for row and then populates the data for each row, so the rows array has not been created when heightForRow method gets called. So your app is trying to access a memory location which it does not have the permission to and therefor you get the EXC_BAD_ACCESS message.
How to achieve self sizing TableViewCell in UITableView:
Just set proper constraints for your views contained in TableViewCell's view in StoryBoard. Remember you shouldn't set height constraints to TableViewCell's root view, its height should be properly computable by the height of its subviews -- This is like what you do to set proper constraints for UIScrollView. This way your cells will get different heights according to their subviews. No additional action needed
Make sure Your TableView Delegate are working as well.
if not then
in your story board or in .xib
press and hold Control + right click on tableView drag and Drop to your Current ViewController.
swift 2.0
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60.0;
}
There is no way to call tableView.dequeueReusableCell from within tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath).
So you have to compute the height from the data.
In my case that was not possible because I have a textView in the cell, which size I did not know.
So I come around with the following strategies:
Do not use tableView.dequeueReusableCell. Just use an array of cells yo have under full control. If your cell is not too large in memory and you don't have too much rows, this is the simplest strategy.
Use a dummy cell, configure it with your data and compute the size.
Try code like this copy and paste in the class
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
Related
I would like to update the content of my custom cell with his height so I wrote this code :
extension MyViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
in my customCellTableView xib i added the top,right,left,bottom constraint to all the labels and also the numberOflines properties to 0
but when t run the app i got a cell of 250 height to all the cells which is very abnormal. I work on Xcode 9 and swift 4.
please if someone can help me,
I have about 3 or 4 table controllers that will all use the same tableview cell. I keep going back on fourth of the possible logic. Can I use the same tableViewCell in multiple tableView Controllers assuming the information is between the two is the same? Or will I have to create a new cell for each controller?
Yes you can.
I am assuming that you are using Swift.
Goto File -> New and select cocoaTouch class as follows.
Now name Your class for custom cell and make it subClass of UITableViewCell. also check the box which says "Also create Xib file"
Now design your cell in this Xib and create outlets in its .Swift file. Lets say you have a custom tableView cell which looks something like this
Which contains a label or ImageView or anyThing that you have in your cell. Now in your swift file of custom cell you can write a method like so
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: NSIndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.registerNib(UINib(nibName: "YourCustomTableViewCell", bundle: NSBundle.mainBundle()), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCellWithIdentifier(kYourCustomTableViewCellIdentifier, forIndexPath: indexPath) as! YourCustomTableViewCell
return cell
}
Now you can use this cell in any tableView in your application just like below
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = YourCustomTableViewCell.cellForTableView(tableView, atIndexPath: indexPath)
cell.backgroundColor = UIColor.clearColor()
// do something with your cell
}
I hope it helps.
Update for Swift 3 and Swift 4:
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> YourCustomTableViewCell {
let kYourCustomTableViewCellIdentifier = "kYourCustomTableViewCellIdentifier"
tableView.register(UINib(nibName: "YourCustomTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: kYourCustomTableViewCellIdentifier)
let cell = tableView.dequeueReusableCell(withIdentifier: kYourCustomTableViewCellIdentifier, for: indexPath) as! YourCustomTableViewCell
return cell
}
Yes you can use the table view cell in multiple tableView Controllers .
I have created a UICollectionView in which I have one prototype cell. I want 2 cells per row and running it on smaller screen gives me on one cell per row.
The distance between cells gets increased on bigger screen. I am talking only with respect to iPhones.
I think I have to set constrains programmatically by taking screen width and divide it by 2. I know how to take screen width and divide it by 2 but I don't know how to give width and heights to cell programmatically.
UICollectionViewDelegateFlowLayout defines a method for this purpose.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
// return a CGSize
}
Example:
class MyViewController : UIViewController, UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView.delegate = self
self.collectionView.dataSource = self
}
// ...
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: CGFloat(self.view.frame.size.width / 2), height: self.view.frame.size.height)
}
// ...
}
I have Constraints set for the image view in the background but for some reason when I swipe to get the Delete the image gets resized.
First Try to changing your imageView content mode to .AspectFit. The second image is actually correct if you want the whole image to show. It looks like it's redrawing image when it starts becoming interactive. Try calling cell.yourImageView.layoutIfNeeded() when loading the cell to fix your problem. If this is a UIViewController and that does not work try moving the code for autodiminsions to the actual functions.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return closeGuess //maybe 200
}
I'm trying to figure out how to make a table of images with varying sizes. Where the images get resized to fit the width of the device, and the cells fit the height of the image. Currently the images are getting sized to the table cells.
Xcode project
ViewController
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var images = ["abstract","city","city2","nightlife"]
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! ImageTableViewCell
cell.configureCellWith(images[indexPath.item])
return cell
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return images.count
}
}
ImageTableViewCell
import UIKit
class ImageTableViewCell: UITableViewCell {
#IBOutlet weak var tableImage: UIImageView!
func configureCellWith(image: String) {
tableImage.image = UIImage(named: image)
}
}
Implement heightForRowAtIndexPath to set the cell height to the correct height for that cell's image.
(You can determine that height by examining the image's width and height, and divide to give the aspect ratio. Now use that aspect ratio to determine the height based on the cell width, which is the table width.)
This is actually fairly simple. You just have to implement heightForRowAtIndexPath function and return height of image for each cell.
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return image[indexPath.row].size.height
}