简体   繁体   中英

Swift UITableViewCell Dynamic Cell Height on Runtime

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 (eg 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 -

  1. When tableview will be scrolled.
  2. 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:

  1. Create another UITableViewCell in the UITableView via the Storyboard. That TableView cell has the custom height you need.
  2. Create a new UITableViewCell class file.
  3. Assign the new class to the cell in the storyboard.
  4. Call TableView.reloadData() when Options is pressed. And turn a Bool to true for the selected cell.
  5. In the cellForRowAtIndexPath() use the custom UITableViewCell class when the Bool is on true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM