I'm trying to have a UITableViewCell reveal more content about a particular cell whenever that specific cell is tapped. Once the cell has expanded and is tapped again, the cell should shrink back to its original size.
I'm pretty sure something has to be done with the delegates heightForRowAtIndexPath and didSelectRowAtIndexPath, but I don't know how to select a specific table cell row using didSelectRowAtIndexPath.
// Height of table cell rows
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 45
}
//On cell tap, expand
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.rowHeight = 75;
}
Also, is it possible to hide any content that's overflowing from the parent cell? Kind of like overflow: hidden; in CSS.
Declare a global variable NSInteger type and store row on tableview selected in didSelectRowAtIndexPath and also reload here . After check row in heightForRowAtIndexPath and increase height there .
Try Like this
var selectedIndex : NSInteger! = -1 //Delecre this global
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == selectedIndex{
selectedIndex = -1
}else{
selectedIndex = indexPath.row
}
tableView.reloadData()
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == selectedIndex
{
return 75
}else{
return 45
}
}
What you have to do is to save the index of the selected Cell in didSelectRow method. and also have to begin/end updates on table view. This will reload some part of tableview. and will call heightForRow method. In that method you can check that if your row is selected one then return expandedHeight, otherwise return the normal height
In height for row:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if self.selectedSortingRow == indexPath.row {
return ExpandedRowHeight
}
else{
return normalHeight
}
}
In didSelect Row:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.beginUpdates()
selectedSortingRow = (int) indexPath.row
self.tableView.endUpdates()
}
Swift 4 answer with recommended comments. No need to make a new variable, tableView holds a value for selectedRow indexPath.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if self.tableView.indexPathForSelectedRow?.row == indexPath.row {
return 75;
} else {
return 45;
}
}
Swift 4. Animated resize with multiple selection. Based on Ryderpro answer.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.beginUpdates()
tableView.endUpdates()
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let selectedRows = tableView.indexPathsForSelectedRows, selectedRows.contains(indexPath) {
return 75
} else {
return 45
}
}
Related
I have some problems with reloading section in tableView. If the cell is hiding a bit on the top, it becomes flicking. If the cell is fully visible, everything works fine. The height of cell is fixed, and it's not automaticDimension. All of cells are standard UITableViewCell with different background color. I know that tableView is a very common UI element in ios, and I hope someone had faced the same problem before. Thanks!
func numberOfSections(in tableView: UITableView) -> Int {
return contactsForSections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let contact = contactsForSections[section]
return contact.isExpanded ? contact.numbers.count : 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = UITableViewCell()
cell.contentView.backgroundColor = .green
return cell
} else {
let cell = UITableViewCell()
cell.contentView.backgroundColor = .red
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
guard indexPath.row == 0 else { return }
contactsForSections[indexPath.section].isExpanded.toggle()
tableView.reloadSections([indexPath.section], with: .none)
}
I have a tableView that expands cell height when user taps on cell. The problem is in some cells after expanding cell height tableView scrolls very higher or lower the selectedCell I mean it miss the current cell position
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if cellsMode[indexPath.row] {
return 344
}
else {
return 140 }
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.cellsMode[indexPath.row] = !self.cellsMode[indexPath.row]
table.reloadData()
}
I tried to use
let indexPath = NSIndexPath(row: cellInex, section: 0)
self.table.scrollToRow(at: indexPath as IndexPath, at: .bottom, animated: false)
but it not worked.
How can i fixed it?
Just reload cell not entire tableview, like bellow:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.cellsMode[indexPath.row] = !self.cellsMode[indexPath.row]
tableView.reloadRows(at: [indexPath], with: .automatic)
}
I'm calling a TableView inside of a custom ViewController. In my UITableView, my cells overlap. Like so
In the storyboard editor, I have the Row Height set to Custom at 63pts, but they look like they're actually using the the default height that the cell would be if you unchecked the Custom box.
Like in some of the other solutions tried implementing the heightForRowAt function but it doesn't do anything. I've tried using obscenely large numbers, but the result is always exactly as it was before.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if(self.view.traitCollection.horizontalSizeClass == .compact ||
self.view.traitCollection.verticalSizeClass == .compact) {
cellHeight = 55
return 55
}
else{
return 63
}
}
The only thing in solutions I've seen so far that looks at all promising is this one. iOS UITableViewCell overlapping
I've tried implementing the prepareForReuse Function in my custom TableViewCell class file, but I didn't know what I was actually supposed to add to the function, so I just called the super function and added a print statement
--- Full TableView Code ---
extension SavingViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "WishlistTableViewCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? WishlistTableViewCell else {
fatalError("The dequeued cell is not an instance of WishlistTableViewCell.")
}
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
if(self.view.traitCollection.horizontalSizeClass == .compact ||
self.view.traitCollection.verticalSizeClass == .compact) {
cellHeight = 55
return 55
}
else{
return 63
}
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
/*
let resultRemoving = bookmarks[indexPath.row]
if var bookmarkData = defaults.object(forKey:"bookmarkDict") as? [String: [String]] {
bookmarkData.removeValue(forKey: resultRemoving.resultURL)
defaults.set(bookmarkData, forKey:"bookmarkDict")
}
defaults.synchronize()
*/
items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
}
Currently heightForRowAt is not being called since heightForRowAt method is a UITableViewDelegate method so
Your extension should look like this:
Add UITableViewDelegate
extension SavingViewController: UITableViewDataSource, UITableViewDelegate {
}
I have two cells (one dynamic and other static) and I want to set different height for each cell like:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
/*tableView.dequeueReusableCell(withIdentifier: "Cell1", for: indexPath)
tableView.dequeueReusableCell(withIdentifier: "Cell2", for: indexPath)
if cell1 return 100
if cell2 return 20 */
}
It's possible to specific height for each cell not row.
How can I resolve this issue?
For static cell (created either as Xib or in storyboard), you can set the height like this, if you are displaying static cell in first row of your Table View.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.row == 0 {
return 120
}
return UITableViewAutomaticDimension
}
To populate the static cell along with dynamic cell, You should do,
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasource.count + 1
}
UITableViewAutomaticDimension
https://www.raywenderlich.com/129059/self-sizing-table-view-cells -
If you set correctly the autolayout for the cell you can use UITableViewAutomaticDimension to have the size without have to specify.
You only need to return a height for each indexPath. There is no need to dequeue a cell here. If you want different prototype cells you will do this in cellForRowAtIndexPath.
You can specify as many sections and rows as you want:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
switch indexPath.section {
case 0:
switch indexPath.row {
case 0:
return 100.0
case 1:
return 20.0
// Add rows here if needed
default:
return UITableViewAutomaticDimension
// Add sections here if needed
default:
default:
return UITableViewAutomaticDimension
}
}
*In, Swift 3.0
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
} else {
return 200
}
}
or you can set Constraint of your Cell proper and then write this code of your ViewDidLoad Method
yourTblView.estimatedRowHeight = 100
yourTblView.rowHeight = UITableViewAutomaticDimension*
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
} else {
return 20
}
}
I would like something like the following:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("NewsCell", forIndexPath: indexPath) as! UITableViewCell
if indexPath == 3{
cell.height = "50dp"
}
return cell
}
what is the alternative or the easiest way to go about this?
EDIT
Is it possible for me to also specify section number: i.e-
if sectionIndex == 5
I suggest use the heightForRowAtIndexPath function. TableView will call this function to determine the row height for a specific indexpath.
Sample code:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if indexPath.section == SECTION_INDEX {
return 60
} else {
return UITableViewAutomaticDimension
}
}
Swift 4:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == SECTION_INDEX {
return 60
} else {
return UITableViewAutomaticDimension
}
}
A little explain:
indexPath have two properties: section and row. By checking these two properties, you can make your own control flow to determine the height for each cell.
If you return 60, it means you want the cell's height to be 60 points. If you return UITableViewAutomaticDimension, you want the system to decide the best height for you (in this case, you'd better set autolayout for the cell in storyboard).
I also suggest you take the stanford course CS193p on iTunes U, it would be of great help to you :)
the easiest way is to override heightForRowAtIndexPath
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let section = indexPath.section
let row = indexPath.row
if section == 0 && row == 2{
return 50.0
}
return 22.0
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
if indexPath.section == 5
{
if indexPath.row == 3
{
return 150.0
}
}
return 200.0
}
Following Zhu Shengqi's answer, here is the Swift 5+ code.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == SECTION_INDEX {
return 160
} else {
return UITableView.automaticDimension
}
}
the easiest way is to override heightForRowAtIndexPath delegate method is there in tableview.
These method based on content it will change the height automatically.
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableView.AutoDiemensions
}