Swift: How to reload row height in UITableViewCell without reloading data - swift

I have a case in which I have to reload only height of a UITableViewCell.
but if I call the function
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: webView.tag, inSection: 0)], withRowAnimation: .Automatic)
it reloads the height as well as the data of the cell.
How can i just control the height of cell in Swift?
This is my cellForRow block :
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = headerText
return cell
}
else if indexPath.row == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell2", forIndexPath: indexPath) as! CustomTableViewCell2
ImageLoader.sharedLoader.imageForUrl(self.headerImage , completionHandler:{(image: UIImage?, url: String) in
cell.mainImage.image = image
})
return cell
}
else if indexPath.row == 2 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell3", forIndexPath: indexPath) as! CustomTableViewCell3
//cell.aurthorImage.image = UIImage(named : "obama")
ImageLoader.sharedLoader.imageForUrl(self.headerImage , completionHandler:{(image: UIImage?, url: String) in
cell.aurthorImage.image = image
})
cell.aurthorImage.tag = aurthorID
cell.aurthorImage.layer.cornerRadius = cell.aurthorImage.frame.height/2
cell.aurthorImage.clipsToBounds = true
cell.aurthorImage.userInteractionEnabled = true
cell.aurthorImage.addGestureRecognizer(aurthorImageTapRecignizer)
cell.aurthorName.text = self.authorName
cell.time.text = self.time
self.followButton = cell.followButton
return cell
}
else if indexPath.row == 3 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell4", forIndexPath: indexPath) as! CustomTableViewCell4
let htmlHeight = contentHeights[indexPath.row]
cell.webElement.tag = indexPath.row
cell.webElement.delegate = self
cell.webElement.loadHTMLString(HTMLContent, baseURL: nil)
cell.webElement.frame = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
return cell
}
else if indexPath.row == 4 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = "Related Posts"
return cell
}
else if indexPath.row == 5{
let cell = tableView.dequeueReusableCellWithIdentifier("cell6", forIndexPath: indexPath) as! CustomTableViewCell6
return cell
}
else if indexPath.row == 6 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = "Comments"
return cell
}
else if indexPath.row == 7 {
let cell = tableView.dequeueReusableCellWithIdentifier("cell5", forIndexPath: indexPath) as! CustomTableViewCell5
let htmlHeight = contentHeights[indexPath.row]
self.commentSection = cell.commentsView
self.commentSection.tag = indexPath.row
self.commentSection.delegate = self
let url = NSURL(string: commentsURL)
let requestObj = NSURLRequest(URL: url! )
self.commentSection.loadRequest(requestObj)
self.commentSection.frame = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
commentSectionDidNotLoad = false
return cell
}
else {
let cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! CustomTableViewCell1
cell.heading.text = headerText
return cell
}

You can use this code to update the cell's height without reloading their data:
tableView.beginUpdates()
tableView.endUpdates()
You can also use this method followed by the endUpdates method to animate the change in the row heights without reloading the cell.
UITableView Class Reference

start an update of the tableview and then end it without changing anything.
tableView.beginUpdates()
tableView.endUpdates()
This should make the tableview set the new height
You can regulate the height by either implementing the (a)heightForRowAtIndexPath with logic setting the heights or (b)with auto layout and automatic tableview row height
A.
override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
if [your condition, row == 5 in your comment] {
return 100
} else {
return 40
}
}
Whenever you want to change the height you would just call these two rows
tableView.beginUpdates()
tableView.endUpdates()
B.
in viewDidLoad
tableView.estimatedRowHeight = 40.0
tableView.rowHeight = UITableViewAutomaticDimension
and then you can just expose the layout constraint that set's the cells height and access it to set the height when you want
cell.heightConstraint.constant = 100
tableView.beginUpdates()
tableView.endUpdates()

About your question for example, to give a specific height dimension :
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 3 {
return 50.0
}
return 72.0
}
But I think you have a webView inside a cell so, generally, to calculate the dynamic height of a UITableViewCell with a UIWebView:
(this example have two webViews)
class MyTableViewController: UITableViewController, UIWebViewDelegate
{
var content : [String] = ["<!DOCTYPE html><html><head><title>Page Title</title></head><body><h1>My First Heading</h1><p>My first paragraph</p></body></html>", "<HTML><HEAD><TITLE>Coca-Cola</TITLE></HEAD><BODY>In Chinese, Coca-Cola means Bite the Wax Tadpole</BODY></HTML>"]
var contentHeights : [CGFloat] = [0.0, 0.0]
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCellWithIdentifier("myCustomCell", forIndexPath: indexPath) as! MyCustomCell
let htmlString = content[indexPath.row]
let htmlHeight = contentHeights[indexPath.row]
cell.webView.tag = indexPath.row
cell.webView.delegate = self
cell.webView.loadHTMLString(htmlString, baseURL: nil)
cell.webView.frame = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return contentHeights[indexPath.row]
}
func webViewDidFinishLoad(webView: UIWebView)
{
if (contentHeights[webView.tag] != 0.0)
{
// height knowed, no need to reload cell
return
}
contentHeights[webView.tag] = webView.scrollView.contentSize.height
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: webView.tag, inSection: 0)], withRowAnimation: .Automatic)
}
}

You can use the view height constraint in the cell, by updating the view in cell height you can update the specific cell height.
let height = cell.Height_constraint.constant
cell.Height_constraint.constant = height + 200 //200 you can use any number
Height_constraint: is the height constraint of subView in my cell.

Related

UITableViewController insert different cells into different sections

I have a TableViewController with 3 sections with their own headers.
Now I want before inserting any cell, check a property and then add the cell into different sections.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Table view cells are reused and should be dequeued using a cell identifier.
let cellIdentifier = "TasksTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? TasksTableViewCell else {
fatalError("The dequeued cell is not an instance of TasksTableViewCell.")
}
// Fetches the appropriate task for the data source layout.
let task = tasks[indexPath.row]
cell.nameLabel.text = task.name
cell.photoImageView.image = task.photo
cell.timeControl.text = task.lengthDisplay.replacingOccurrences(of: "Length: ", with: "")
if(task.importanceLevel == 0){
// add cell to section 0
}
else if(task.importanceLevel == 1){
// add cell to section 1
}
// Configure the cell...
return cell
}
Can u see the comment, is there any way to do that?
Thank you very much
You can create a model and pass empty count arrays at first for each section and row in data source methods.
And then initialize the count and fill arrays their then reload your table view.
I hope you know there is numberOfSections method too.
I think this code will help you:
let arr = [5,2,7,10,2]
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 5
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return arr[section]
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("celldata", forIndexPath: indexPath)
cell.textLabel?.text = "section \(indexPath.section)"
cell.detailTextLabel?.text = "Rows \(indexPath.row)"
return cell
}
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let view = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.frame.width, height: 20))
let lbl = UILabel(frame: CGRect(x: 5, y: 5, width: self.tableView.frame.width, height: 15))
lbl.text = "\(section)"
view.backgroundColor = UIColor.grayColor()
view.addSubview(lbl)
return view
}
You can try it like this
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.section == 0){
let cellIdentifier = "TasksTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? TasksTableViewCell else {
fatalError("The dequeued cell is not an instance of TasksTableViewCell.")
}
// Fetches the appropriate task for the data source layout.
let task = tasks[indexPath.row]
cell.nameLabel.text = task.name
cell.photoImageView.image = task.photo
cell.timeControl.text = task.lengthDisplay.replacingOccurrences(of: "Length: ", with: "")
return cell
}
else if(indexPath.section == 1)
let cellIdentifier = "TasksTableViewCell1"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? TasksTableViewCell1 else {
fatalError("The dequeued cell is not an instance of TasksTableViewCell.")
}
// Fetches the appropriate task for the data source layout.
let task = tasks[indexPath.row]
cell.nameLabel.text = task.name
cell.photoImageView.image = task.photo
cell.timeControl.text = task.lengthDisplay.replacingOccurrences(of: "Length: ", with: "")
return cell
}
}

Wondering if this is the best way to execute this. tableview switching cell sizes

I have a tableview with two prototype cells that share identical information. When i tap the "CardList" button all the cells go from one cell size to a smaller size and then vice versa when i tap it again. the first transition works fine but going back from the smaller cell to the larger one the, the cells height is only about 50 pts instead of the 338 that i have set. Also, wondering if this is the best way to do this by having two different cells. Should i just have one cell and rearrange it?
var CellSize = Int()
#IBAction func CardList(sender: AnyObject){
if (sender.titleLabel!?.text == "Card")
{
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 338
self.CellSize = 2
self.tableView.reloadData()
sender.setTitle("List", forState: UIControlState.Normal);
}
else
{
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 142
self.CellSize = 1
self.tableView.reloadData()
sender.setTitle("Card", forState: UIControlState.Normal);
}
}
////////////////
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if CellSize == 1 {
let cell = self.tableView.dequeueReusableCellWithIdentifier(
"ResultsCell2", forIndexPath: indexPath)
as! ResultsCell2
let row = indexPath.row
cell.Name.text = Names[row]
cell.Image.image = UIImage(named: Images[row])
cell.Price.text = Prices[row]
return cell
}
else
{
let cell2 =
self.tableView.dequeueReusableCellWithIdentifier(
"ResultsCell", forIndexPath: indexPath)
as! ResultsCell
let row = indexPath.row
cell2.Name.text = Names[row]
cell2.Image.image = UIImage(named: Images[row])
cell2.Price.text = Prices[row]
return cell2
}
}
Well to set a cellRow's height in a proper way you should use this method:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if CellSize == 1 {
return 338
}
return 50
}
Note: UITableViewDelegate method and to be able to use it you should set your tableView's delegate to your own class and call this method there.

How to Set data to second tableview in same Class in swift

How to Set data to second tableview in same Class in swift.I am using two tables in the the same controller one for dropdown and another for listing. I am unable to set data to second table(listing) in class
as else part is not called in cellForRowAtIndexPath. Thanks in Advance
import UIKit
class PunchClockVC: UIViewController , UITableViewDataSource, UITableViewDelegate{
var appdel = UIApplication.sharedApplication().delegate as! AppDelegate
#IBOutlet weak var dropdownTable: UITableView!
#IBOutlet weak var mainTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.mainTable.registerClass(PunchClockCustomCell.self, forCellReuseIdentifier: "PunchClockCustomCell")
self.dropdownTable.registerClass(UITableViewCell.self, forCellReuseIdentifier: "dropdowncell")
self.dropdownTable.hidden = true
}
#IBAction func textFieldTapped(sender: AnyObject) {
if self.dropdownTable.hidden == true {
self.dropdownTable.hidden = false
}
else{
self.dropdownTable.hidden = false
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == dropdownTable {
return jobArrayID.count
}
return 8
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.dropdownTable {
let cell = tableView.dequeueReusableCellWithIdentifier("dropdowncell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = (jobArrayID[indexPath.row] as! String) + "-" + (jobArrayName[indexPath.row] as! String)
return cell
}
else {
let cell1 = tableView.dequeueReusableCellWithIdentifier("PunchClockCustomCell", forIndexPath: indexPath) as! PunchClockCustomCell
if indexPath.row == 0
{
cell1.jobcell?.font = UIFont(name: "MuseoSlab-500", size: 25.0)
cell1.locationcell?.font = UIFont(name: "MuseoSlab-500", size: 25.0)
cell1.timecell?.font = UIFont(name: "MuseoSlab-500", size: 25.0)
cell1.typecell?.font = UIFont(name: "MuseoSlab-500", size: 25.0)
cell1.jobcell?.textColor = UIColor.blackColor()
cell1.locationcell?.textColor = UIColor.blackColor()
cell1.timecell?.textColor = UIColor.blackColor()
cell1.typecell?.textColor = UIColor.blackColor()
cell1.jobcell?.text = "Job"
cell1.locationcell?.text = "Location"
cell1.timecell?.text = "Time"
cell1.typecell?.text = "Type"
// return cell1
}
else {
cell1.jobcell?.text = "Jobdata"
cell1.locationcell?.text = "Locationdata"
cell1.timecell?.text = "Timedata"
cell1.typecell?.text = "OUT"
// return cell1
}
return cell1
}
}
It's quite simple You need to set it only with cellForRowAtIndexPath method but the main thing to do is you need to code like below
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
if tableView == firstTbaleView
//outlet given to first tableView
{
let cell = tableView.dequeueReusableCellWithReuseIdentifier("cell1", forIndexPath: indexPath) as! cust1TableViewCell
cell.imgView.image = images[indexPath.row]
cell.filtLabel.text = self.filtersCount[indexPath.row]
return cell
}}else {
let cell2 = tableView.dequeueReusableCellWithReuseIdentifier("cell2", forIndexPath: indexPath) as! cust2TableViewCell
cell2.imgview.image = UIImage(named: colPhotos[indexPath.row])
cell2.labl.text = colNames[indexPath.row]
// cell2.layer.borderColor = UIColor.blueColor().CGColor
// cell2.layer.borderWidth = 2.0
return cell2
}
and that's it you can ask me for any help..
Lets make this a little safer:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if tableView == self.dropdownTable {
return jobArray.count
}
else if tableView == self.mainTable {
return = 5
}
//Default return 0. This way if references are broken or change, you won't crash
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView == self.dropdownTable {
let cell = tableView.dequeueReusableCellWithIdentifier("dropdowncell", forIndexPath: indexPath) as! UITableViewCell
//configure your cell
return cell
}
else if tableView == self.mainTable {
let cell = tableView.dequeueReusableCellWithIdentifier("PunchClockCustomCell", forIndexPath: indexPath) as! PunchClockCustomCell
//configure your cell
return cell
}
//Shouln't ever reach here, but again, if we refactor somewhere then we'll see an error show up before here.
return UITableViewCell()
}

Dynamic TableViewCell | Swift

I have 2 custom cells: 1 for image, 2 for text (using label to display).
I want text-cell to be dynamic height, depending on text size.
Set lines of label to 0, used top, left and right constraints, but when i add info to array, reload it - then table displays nothing.
Also in viewDidLoad coded next:
articleTableView.estimatedRowHeight = 150
articleTableView.rowHeight = UITableViewAutomaticDimension
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
if content[indexPath.row].rangeOfString("imageBase64") == nil {
let cell = self.articleTableView.dequeueReusableCellWithIdentifier("Text Cell", forIndexPath: indexPath) as! TextTableViewCell
cell.textArticle.text = content[indexPath.row] as String
}
else{
let cell = self.articleTableView.dequeueReusableCellWithIdentifier("Image Cell", forIndexPath: indexPath) as! ImageTableViewCell
cell.imageArticle.image = decodedImage
}
return UITableViewCell()
}
What's the problem here?
You need to return cell not return UITableViewCell()

Custom Checkbox AccessoryView for UITableView

I am using Custom AccessoryView for UITableViewCell. I am using a checkbox. Here, I want multiple selection. The code works fine while selection but while deselecting it I am having issues. I am not sure what I should be writing in cellForRowAtIndexPathMethod. The issue I am facing is, after deselecting the checkbox, I cannot select it again. Here is my code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let fourthCell = tableView.dequeueReusableCellWithIdentifier("fourthCell", forIndexPath: indexPath) as! ItemDetailFourthTableViewCell
if indexPath != self.lastIndexPath {
fourthCell.accessoryView = UIImageView(image: UIImage(named: "checkBoxPassive.png"))
fourthCell.accessoryView?.tag = 2
}
if indexPath == self.lastIndexPath {
fourthCell.accessoryView = UIImageView(image: UIImage(named: "checkBoxActive.png"))
}
return fourthCell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
self.isSelected = true
self.lastIndexPath == indexPath
if indexPath.section == 1 {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! ItemDetailFourthTableViewCell
print("The cell here is \(cell)")
print("Here the cell accessoryView is \(cell.accessoryView?.tag)")
if cell.accessoryView?.tag == 0 {
print("It is active")
cell.accessoryView = UIImageView(image: UIImage(named: "checkBoxPassive.png"))
} else if cell.accessoryView?.tag == 2 {
print("It is passive")
cell.accessoryView = UIImageView(image: UIImage(named: "checkBoxActive.png"))
}
}
}