Any idea on how I can manage to do the use case I have below. Although I manage to do this using UITableView, I still get some issue every time I scroll the table view.
Scenario: The table view needs to adjust the height of the cell dynamically based on which item is selected. Each item would have different options inside of it. When Options is selected it should be able to show the options under the item and automatically adjust the height.
Solution: I subclassed UITableView and UITableViewCell. Every time Options is selected/tapped I will call beginUpdate and endUpdate which is working perfectly.
Problem: Every time the user scrolls down the options are not showing correctly.
Everytime when you scrolls up or down the uitableview will call the cellForRowAtIndexPath and the tableView will reload.
So in this case you need to track down the cell which is selected before scrolling up or down and after scrolling you just need to replace the states (e.g. heights) with that desired cell.
In my case I am using some veriable to keep track of the hegiht of the cell.
Here is my code below : -
import UIKit
class WaitingListClass: UIViewController,UITableViewDataSource, UITableViewDelegate {
var selectedCellIndexPath: NSIndexPath!
let SelectedCellHeight: CGFloat = 88.0
let UnselectedCellHeight: CGFloat = 44.0
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
let appdelegateObjForThisClass = UIApplication.sharedApplication().delegate as! AppDelegate
tableView.delegate = self
tableView.dataSource = self
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.backgroundColor = UIColor.clearColor()
self.tableView.separatorColor = tableViewSeperatorColor
self.tableView.tableFooterView = UIView(frame: CGRectZero)
self.tableView.contentInset = UIEdgeInsetsZero
}
internal func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return 1
}
internal func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
if noDataForTable == true{
return 1
}
return appdelegateObjForThisClass.nameDataForTable.count
}
internal func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{
let cellIdentifier = "WaitingCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CellClassWaitingList
cell.nameDisplayLbl.text = appdelegateObjForThisClass.nameDataForTable[indexPath.row]["name"]!
cell.backgroundColor = tableViewCellColor
cell.nameDisplayLbl.textColor = UIColor(red: 191/255, green: 193/255, blue: 192/255, alpha: 1)
cell.idDisplayLbl.textColor = UIColor(red: 48/255, green: 143/255, blue: 94/255, alpha: 1)
cell.idDisplayLbl.text = appdelegateObjForThisClass.indexForTable[indexPath.row]
cell.userInteractionEnabled = true
cell.clipsToBounds = true
cell.selectionStyle = UITableViewCellSelectionStyle.None
let heightOfCell : CGFloat = self.tableView.delegate!.tableView!(self.tableView, heightForRowAtIndexPath: indexPath)
if heightOfCell == self.UnselectedCellHeight{
cell.stackOfBtnInCell.hidden = true
}else if heightOfCell == self.SelectedCellHeight{
cell.stackOfBtnInCell.hidden = false
}
return cell
}
internal func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CellClassWaitingList
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
self.selectedCellIndexPath = nil
UIView.animateWithDuration(0.5, animations: {
cell.stackOfBtnInCell.hidden = true
self.view.layoutIfNeeded()
})
} else {
UIView.animateWithDuration(0.5, animations: {
cell.stackOfBtnInCell.hidden = false
self.view.layoutIfNeeded()
})
self.selectedCellIndexPath = indexPath
}
} else {
UIView.animateWithDuration(0.5, animations: {
cell.stackOfBtnInCell.hidden = false
self.view.layoutIfNeeded()
})
selectedCellIndexPath = indexPath
}
tableView.beginUpdates()
tableView.endUpdates()
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(indexPath) as! CellClassWaitingList
cell.stackOfBtnInCell.hidden = true
}
// MARK: - Cell Separator Setting to Full Size
internal func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
if(self.tableView.respondsToSelector(Selector("setSeparatorInset:"))){
self.tableView.separatorInset = UIEdgeInsetsZero
}
if(self.tableView.respondsToSelector(Selector("setLayoutMargins:"))){
self.tableView.layoutMargins = UIEdgeInsetsZero
}
if(cell.respondsToSelector(Selector("setLayoutMargins:"))){
cell.layoutMargins = UIEdgeInsetsZero
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
return SelectedCellHeight
}
}
return UnselectedCellHeight
}
}
Now what I am doing here is taking a variable called selectedCellIndexPath which will take the selected cell's indexpath first. Next I am taking two more variable called SelectedCellHeight and UnselectedCellHeight which generally stores some height value to interchange each other for the cell in some cases like -
When tableview will be scrolled.
When cell will be selected and deselected.
For rest of the implementation try to look over the tableView datasource and delegate methods.
Thank you,
Hope this helped.
you need to keep a list of your cell states and in your table view data source cellAtIndexPath: and heightForCellAtIndexPath: you should respectively format your cell and specify the desired cell height.
You could create an NSMutableSet and add/remove NSIndexPath objects to it, or use an NSMutableDictionary and check whether a certain key corresponding to a cell's index has a value.
what do you mean "the options are not showing correctly"?
Also, how I would do it:
Create another UITableViewCell in the UITableView via the Storyboard. That TableView cell has the custom height you need.
Create a new UITableViewCell class file.
Assign the new class to the cell in the storyboard.
Call TableView.reloadData() when Options is pressed. And turn a Bool to true for the selected cell.
In the cellForRowAtIndexPath() use the custom UITableViewCell class when the Bool is on true.
Related
I have one custom style UITableviewCell and it have default height for other I am using tableview cell with style of subtitle and I want to make subtitle to be multiple lines. And it's doing good but having problem with calculating tableview cell height and I use UITableviewAutomaticDimension but its not working.
Here is my code
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if(indexPath.row==0){
var cell: ImageCell! = tableView.dequeueReusableCellWithIdentifier("ImageCell") as? ImageCell
if cell == nil {
tableView.registerNib(UINib(nibName: "ImageCell" ,bundle: nil), forCellReuseIdentifier: "ImageCell")
cell = tableView.dequeueReusableCellWithIdentifier("ImageCell") as? ImageCell
}
return cell
}else{
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("SubtitleCell")
if (cell == nil) {
cell = UITableViewCell.init(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "SubtitleCell")
cell!.backgroundColor = UIColor.brownColor()
cell!.textLabel?.font = UIFont.init(name: "HelveticaNeue", size: 15)
cell!.textLabel?.textColor = UIColor.blackColor()
cell!.textLabel?.highlightedTextColor = UIColor.lightGrayColor()
cell!.selectedBackgroundView = UIView.init()
}
cell!.textLabel?.text = "TExt"
cell!.detailTextLabel!.text="Keep in mind that UITableView is defined as an optional in the function, which means your initial cell declaration needs to check for the optional in the property. Also, the returned queued cell is also optional, so ensure you make an optional cast to UITableViewCell. Afterwards, we can force unwrap because we know we have a cell."
allowMultipleLines(cell!)
cell!.imageView?.image = UIImage(named: "IconProfile")
return cell!
}
}
func allowMultipleLines(tableViewCell:UITableViewCell) {
tableViewCell.detailTextLabel?.numberOfLines = 0
tableViewCell.detailTextLabel?.lineBreakMode = NSLineBreakMode.ByWordWrapping
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(indexPath.row==0){
return 172
}else{
return UITableViewAutomaticDimension
}
}
in your viewDidLoad() Method you need to write
yourTableViewName.rowHeight = UITableViewAutomaticDimension
And Add One more method
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if(indexPath.row==0){
return 172
}else{
return UITableViewAutomaticDimension;
}
}
i hope this will help you
I'm trying to get my tableview to work so when a cell is clicked it resizes to fit the content inside the cell automatically. (Different amounts of text will automatically re-size different.
Cell when not clicked (first state and size it should go back to when clicked = 44.0
So with this image, this is the stage each cell will be in only as default and deselected. The white text will be the only thing visible.
Cell clicked state. resizes to my "let selectedCellHeight: CGFloat = 88.0
" constant. Which needs to automatically size to fit the green text no matter how much is in there.
This is my full code for the tableview and viewcontroller.
import UIKit
class TasksViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tblTasks: UITableView!
//For persisting data
let defaults = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
self.tblTasks.backgroundColor = UIColor(red: 64/255.0, green: 67/255.0, blue: 68/255.0, alpha: 0)
self.tblTasks.reloadData()
self.tblTasks.register(UINib(nibName: "WhiteTaskTableViewCell", bundle: nil), forCellReuseIdentifier: "nameCell")
tblTasks.tableFooterView = UIView()
let darkModeColor = UIColor(red: 52/255.0, green: 55/255.0, blue: 55/255.0, alpha: 1.0)
view.backgroundColor = darkModeColor
tblTasks.dataSource = self;
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
self.tblTasks.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return taskMgr.tasks.count
}
//Define how our cells look - 2 lines a heading and a subtitle
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let identifier = "nameCell"
var cell: WhiteTaskTableViewCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? WhiteTaskTableViewCell
if cell == nil {
tableView.register(UINib(nibName: "WhiteTaskTableViewCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as? WhiteTaskTableViewCell
}
// Assign the contents of our var "items" to the textLabel of each cell
// cell.textLabel!.text = taskMgr.tasks[indexPath.row].name
// cell.detailTextLabel!.text = taskMgr.tasks[indexPath.row].desc
cell.TaskNameLabel.text = taskMgr.tasks[indexPath.row].name
cell.NotesLabel.text = taskMgr.tasks[indexPath.row].note
cell.selectionStyle = .none
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func tableView(_ willDisplayforRowAttableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.backgroundColor = UIColor(red: 64/255.0, green: 67/255.0, blue: 68/255.0, alpha: 0)
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
// handle delete (by removing the data from your array and updating the tableview)
taskMgr.removeTask(indexPath.row)
tblTasks.reloadData()
}
}
// EXPAND CELL ON CLICK
// Global Variables/Constants
var selectedCellIndexPath: NSIndexPath?
let selectedCellHeight: CGFloat = 88.0
let unselectedCellHeight: CGFloat = 44.0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
self.tblTasks.rowHeight = UITableViewAutomaticDimension
if selectedCellIndexPath == indexPath as NSIndexPath? {
return selectedCellHeight
}
return unselectedCellHeight
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedCellIndexPath != nil && selectedCellIndexPath == indexPath as NSIndexPath? {
selectedCellIndexPath = nil
} else {
selectedCellIndexPath = indexPath as NSIndexPath?
}
tableView.beginUpdates()
tableView.endUpdates()
if selectedCellIndexPath != nil {
// This ensures, that the cell is fully visible once expanded
tableView.scrollToRow(at: indexPath as IndexPath, at: .none, animated: true)
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
I'm open to any help and insight. Thank you very much.
You need to set an Outlet to your UITableView and set the rowHeight parameter to UITableViewAutomaticDimension. Also you need set the estimatedRowHeight to a value fitting your needs. This way the size of the Cell will fit the size of its content.
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 55
tableView.rowHeight = UITableViewAutomaticDimension
}
For this to work, you need to set the Autolayout Constraints for every element of your Cell.
Source Apple Doc:
Working with Self-Sizing Table View Cells
In iOS, you can use Auto Layout to define the height of a table view
cell; however, the feature is not enabled by default.
Normally, a cell’s height is determined by the table view delegate’s
tableView:heightForRowAtIndexPath: method. To enable self-sizing table
view cells, you must set the table view’s rowHeight property to
UITableViewAutomaticDimension. You must also assign a value to the
estimatedRowHeight property. As soon as both of these properties are
set, the system uses Auto Layout to calculate the row’s actual height.
Additionally, try to make the estimated row height as accurate as
possible. The system calculates items such as the scroll bar heights
based on these estimates. The more accurate the estimates, the more
seamless the user experience becomes.
I am using a popover tableview in my project. I want to change the tableview cell's text colour from grey to red on selection. And i also want the highlighted color to remain red when the popover tableview is loaded next time like left menu selection. Need help to do this. I have provided the code for the popover tableview.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if tableView === tableViewPopOver {
let cell = UITableViewCell(style: .Default, reuseIdentifier: nil)
cell.textLabel?.text = FeedFilter.allValues[indexPath.row].rawValue
if indexSelected == indexPath.row {
cell.textLabel?.textColor = UIColor.redColor()
} else {
cell.textLabel?.textColor = UIColor.lightGrayColor()
}
//cell.selectionStyle = .None
return cell
}
let cell = tableView.dequeueReusableCellWithIdentifier(kDreamFeedTableViewCell, forIndexPath: indexPath) as! DreamFeedTableViewCell
cell.selectionStyle = .None
let dream = self.arrayDreams[indexPath.row]
cell.dream = dream
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if tableView === tableViewPopOver {
//tableViewPopOver?.cellForRowAtIndexPath(indexPath)?.textLabel?.highlightedTextColor = UIColor.redColor()
//selectedIndexPath = indexPath.row
let cell = tableView.cellForRowAtIndexPath(NSIndexPath.init(forRow: indexSelected, inSection: 0))
cell?.textLabel?.textColor = UIColor.lightGrayColor()
let cell2 = tableView.cellForRowAtIndexPath(indexPath)
cell2?.textLabel?.textColor = UIColor.redColor()
tableView.deselectRowAtIndexPath(indexPath, animated: true)
indexSelected = indexPath.row
self.popover.dismiss()
NRLoader.showLoader()
self.searchDreams(true)
}
else { // dream feed tableview
tableView .deselectRowAtIndexPath(indexPath, animated: false)
let dream = self.arrayDreams[indexPath.row]
if !isValidUser(dream.user) {
return
}
if isCurrentUser(dream.user)
{
self.pushToUserDreamViewControllerForDream(dream)
}
else
{
tableView .deselectRowAtIndexPath(indexPath, animated: false)
self.pushToFeedDetailViewControllerForDream(dream)
}
}
}
I see a problem with your code relate to tableViewPopOver. If you set selection style is .None. You can't select cell.
With your problem I can suggest for you two way to resolve:
If you want use cell.textLabel?.highlightedTextColor you will have face a problem: background of cell will be grey or blue depend on style selection you select. If you can accept it. You can implement like this:
You create a variable to hold a cell selected. Maybe it is int value like var indexSelected = 3. And when you implement cellForRowAtIndexPath you should implement like this:
cell.textLabel?.text = FeedFilter.allValues[indexPath.row].rawValue
cell.textLabel?.highlightedTextColor = UIColor.redColor()
if indexPath.row == indexSelected {
tableView.selectRowAtIndexPath(indexPath, animated:true, scrollPosition: .None)
}
return cell
And in didSelectRowAtIndexPath you update indexSelected:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
indexSelected = indexPath.row //update selected row
}
If you don't want cell background change color. You can choose this way. You should create variable like the way above. But in cellForRowAtIndexPath you should implement:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")//init cell it depend on your way create cell
cell?.textLabel?.text = "Your text"
if indexSelected == indexPath.row {
cell?.textLabel?.textColor = UIColor.redColor()
} else {
cell?.textLabel?.textColor = UIColor.lightGrayColor()
}
return cell!
}
and in didSelectCellAtIndexPath you should implement:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath.init(forRow: indexSelected, inSection: 0))
cell?.textLabel?.textColor = UIColor.lightGrayColor()
let cell2 = tableView.cellForRowAtIndexPath(indexPath)
cell2?.textLabel?.textColor = UIColor.redColor()
tableView.deselectRowAtIndexPath(indexPath, animated: true)
indexSelected = indexPath.row //update selected row
}
Here Demo: Demo
Hope this help!
To change cell's text colour to red on selection you need to implement didSelectRowAtIndexPath and change the cell text Color to red, but it will not stay red when you open it the next time. to handle that you need to have a member variable selectedIndexPath. So it will be something like this
var selectedIndexPath:NSIndexPath!
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.textLabel?.highlightedTextColor = UIColor.redColor()
selectedIndexPath = indexPath
}
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
if let cell = tableView.cellForRowAtIndexPath(indexPath) {
cell.textLabel?.highlightedTextColor = UIColor.grayColor()
selectedIndexPath = nil
}
}
And to load the table next time with the selected cell red text colour you need to add this line in your cellForRowAtIndexPath
Cell
cell.textLabel?.highlightedTextColor = indexPath == selectedIndexPath ? UIColor.redColor() : UIColor.grayColor()
}
I have a UITableView with 3 prototyped cells (ex. 1st cell: image, 2nd cell: Description, 3. Links,...).
I would like to hide them if for a cell the data from the backend is empty (Ex. if there is no image, hide the first cell). In order to do that, I have override the heightForRowAtIndexPath function in this way:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
switch (indexPath.row) {
case 0:
if event?.photo_urls.count == 0{
return 0
}
else{
return 80.0
}
case 1:
if event?.description == ""{
return 0
}
else{
return 90.0
}
default:
return 100.0
}
}
and hidden the cell by doing
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
switch (indexPath.row) {
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("PhotoCell", forIndexPath: indexPath) as! UITableViewCell
if event?.photo_urls.count != 0 {
// ...
}
else{
cell.hidden = true
}
return cell
case 1:
let cell = tableView.dequeueReusableCellWithIdentifier("DesCell", forIndexPath: indexPath) as! UITableViewCell
if event?.description != "" {
// ...
}
else{
cell.hidden = true
}
return cell
default:
let cell = tableView.dequeueReusableCellWithIdentifier("PhotoCell", forIndexPath: indexPath) as! UITableViewCell
return cell
}
}
Until here no problem, it works properly!
Now, THE PROBLEM is that I would like to make the cells dynamics according to the cell contents (ex. description height). In order to do that, I have used
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 80.0
}
and if I comment the heightForRowAtIndexPath the cells are actually dynamics but I can't hide them anymore.
Do you have any suggestion on how to be able to hide the cells if they are empty and apply the automatic dimension according to their content?
lets say you have dynamic data and you want to show it in tableview so you need to create an array of your data to display.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet
var tableView: UITableView
var items: [String] = ["We", "Heart", "nothing" ,"" ,"imageurl", "", "xyz"]
override func viewDidLoad() {
super.viewDidLoad()
reloadTableAfterSorting()
self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
}
func reloadTableAfterSorting(){
for var i = 0; i < self.items.count; i++
{
if self.items[i] == ""{
self.items.removeAtIndex(2)
}
}
self.tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
println("You selected cell #\(indexPath.row)!")
}
}
For that i recommend you to sort the array before displaying it in the table view. Hiding the cell is not a good idea and its not good according to Apple recommendations. So you can do one thing except hiding the cell: remove the index from the array. In this way you can always have data to show in table and it will behave properly. So don’t try to hide the cell just pop the index from array.
I have a tableView that's populated with data, where all my cells can currently expand / collapse when tapping on the row.
However, the last cell in my UITableView is a different kind of data, and it should not be expandable when tapped on.
I have it set up so only one cell can be expanded at a time, so if another cell is currently expanded and they tap on the last cell in the UITableView that cell should still collapse, but the last one shouldn't expand.
The way I'm checking if it's the last cell that shouldn't be expandable is checking one of it's labels: if cell.tickerLabel.text == " CASH"
Which I can verify is correct and that if statement runs for the last cell.
I've tried a lot of different implementations of inserting that if statement into my code where I expand and collapse my cells. But none of what I tried has worked as intended.
Here's how my code for expanding / collapsing cells looks like:
My didSelectRowAtIndexPath function
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell = tableView.dequeueReusableCellWithIdentifier("com.Stocks.portfolioCell", forIndexPath: indexPath) as! portfolioCell
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
self.selectedCellIndexPath = nil
currentCollapsing = true
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
} else {
lastCollapsing = true
self.selectedCellIndexPath = indexPath
tableView.reloadRowsAtIndexPaths([lastIndexPath], withRowAnimation: .None)
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None)
self.lastIndexPath = indexPath
}
} else {
selectedCellIndexPath = indexPath
self.lastIndexPath = indexPath
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
}
tableView.beginUpdates()
tableView.endUpdates()
}
My heightForRowAtIndexPath function
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let SelectedCellHeight: CGFloat = 210
let UnselectedCellHeight: CGFloat = 50
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
return SelectedCellHeight
}
}
return UnselectedCellHeight
}
And lastly the part of my cellForRowAtIndePath function that is relevant to this question:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("com.Stocks.portfolioCell", forIndexPath: indexPath) as! portfolioCell
cell.heightSeperator.hidden = true
cell.stockNameView.hidden = true
cell.purchasePriceView.hidden = true
cell.lastPriceView.hidden = true
cell.daysHeldView.hidden = true
cell.endSeperator.hidden = true
if indexPath.row % 2 == 0 {
cell.backgroundColor = UIColor.formulaWhiteColor()
} else {
cell.backgroundColor = UIColor.whiteColor()
}
if selectedCellIndexPath == indexPath {
cell.tickerLabel.textColor = UIColor.formulaBlueColor()
cell.heightSeperator.hidden = false
cell.stockNameView.hidden = false
cell.purchasePriceView.hidden = false
cell.lastPriceView.hidden = false
cell.daysHeldView.hidden = false
cell.endSeperator.hidden = false
tableHeight.constant = tableHeight.constant+210
self.scrollView.contentSize = CGSize(width:self.view.bounds.width, height: self.contentView.frame.height)
self.view.setNeedsDisplay()
}
if lastCollapsing == true || currentCollapsing == true {
lastCollapsing = false
currentCollapsing = false
tableHeight.constant = tableHeight.constant-210
self.scrollView.contentSize = CGSize(width:self.view.bounds.width, height: self.contentView.frame.height)
self.view.setNeedsDisplay()
}
}
Can anyone help pointing me in the right direction for how I can make it so my last cell isn't expandable while still allowing any other open cell to collapse when tapping on it?
Any help would be greatly appreciated!
You should check if the indexPath is the last one inside heightForRow.
Since you can select your last row, the logic will identify that the last row is selected and when calculating it's height, it will calculate as if it were selected (which it was). so you should avoid the last row from being expanded by handling it inside your heightForRow delegate method.
Update
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let SelectedCellHeight: CGFloat = 210
let UnselectedCellHeight: CGFloat = 50
//Add this here, where numberOfRows is self explanatory
//So replace it with the actually variable.
if indexPath.row == numberOfRows - 1 {
return UnselectedCellHeight;
}
if let selectedCellIndexPath = selectedCellIndexPath {
if selectedCellIndexPath == indexPath {
return SelectedCellHeight
}
}
return UnselectedCellHeight
}