UITableView set tableview row hidden - ios

I have a custom tableview cell in grouptableview. And I have one hidden. I then have to make it visible. Cell tag is 3.
This is not working my code:
if (self.tableView.tag == 3) {
self.tableView.hidden = NO; //Not working.
}
Just i need make a one row is visible. I hope you understand.

In SWIFT you need to do two things,
HIDE your cell. (because reusable cell may conflict)
Set Height of cell to ZERO.
Look at here,
HIDE you cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let myCell:UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "cellID",for: indexPath) as! UITableViewCell
if(indexPath.row < 2){
myCell.isHidden = true
}else{
myCell.isHidden = false
}
return myCell
}
Set Height of cell to ZERO.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
if(indexPath.row < 2){
rowHeight = 0.0
}else{
rowHeight = 55.0 //or whatever you like
}
return rowHeight
}
Using this you can remove reusable cell conflict issues.
You can do the same for cell?.tag also to hide specific cell by tag.

Pass the cell height zero for that specific cell in the heightForRowAtIndexPath: , it will automatically get hidden:-
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
float heightForRow = 40;
YourCustomCell *cell =(YourCustomCell *)[tableView cellForRowAtIndexPath:indexPath];
if(cell.tag==3)
return 0;
else
return heightForRow;
}
Add the following method to your code , it will do the trick .
Hope it will help you .

please refer this code :-
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section
{
if(section == theSectionWithoutARow)
{
if(shouldRemoveTheRow)
return [theArrayWithTheSectionContents count] - 1;
else
return [theArrayWithTheSectionContents count];
}
// other sections, whatever
}
- (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
// blah blah standard table cell creation
id theCellObject;
if(indexPath.section == theSectionWithoutARow)
{
NSInteger theActualRowToDisplay = indexPath.row;
if(shouldRemoveTheRow && indexPath.row >= theRowIndexToRemove)
{
theActualRowToDisplay = indexPath.row + 1;
}
theCellObject = [theArrayWithTheSectionContents objectAtIndex:theActualRowToDisplay];
}
// now set up the cell with theCellObject
return cell;
}
Hope this help you

Here is my scenario. First of all, my table view is static. And in section "Account", there should alway be only one cell displayed. LoggedInCell is displayed when user is logged in, and unLoggedInCell when user is not logged in.
One solution is to set their height zero, but you may encounter NSContraints error which is complex to be fixed.
My solution is below:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let count = super.tableView(tableView, numberOfRowsInSection: section)
if section == 0 {
return count - 1
}
return count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
if userForApp == nil {
return super.tableView(tableView, cellForRowAt: IndexPath(row: 0, section: 0))
} else {
return super.tableView(tableView, cellForRowAt: IndexPath(row: 1, section: 0))
}
} else {
return super.tableView(tableView, cellForRowAt: indexPath)
}
}
quite simple! yes?
Btw, You may have the cells height problem like me, I mean the two cells (UnLoggedInCell and LoggedInCell) have different height, we should tell the table view object that the value of cells height by doing this:
var originHeightOfUnLoggedInCell: CGFloat = 0.0
var originHeightOfLoggedInCell: CGFloat = 0.0
func recordInitialHeightOfCells() { // called in viewDidLoad()
self.originHeightOfUnLoggedInCell = self.unLoggedInCell.frame.height
self.originHeightOfLoggedInCell = self.loggedInCell.frame.height
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.section == 0 {
if userForApp == nil {
return originHeightOfUnLoggedInCell
} else {
return originHeightOfLoggedInCell
}
} else {
return super.tableView(tableView, heightForRowAt: indexPath)
}
}

Related

How can I set UITableView cell height programmatically in Swift?

How to set view height programmatically? I have this code:
cell.viewMain.frame = CGRectMake(cell.viewMain.frame.origin.x, cell.viewMain.frame.origin.y, cell.viewMain.frame.size.width, 65.0)
But that is not working.
UPDATE:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("updateCell", forIndexPath: indexPath) as! UpdateCell
if self.data[indexPath.row] == "b" {
tbUpdate.rowHeight = 85
cell.viewMain.frame = CGRectMake(cell.viewMain.frame.origin.x, cell.viewMain.frame.origin.y, cell.viewMain.frame.size.width, 65.0)
}else{
tbUpdate.rowHeight = 220
cell.viewMain.frame = CGRectMake(cell.viewMain.frame.origin.x, cell.viewMain.frame.origin.y, cell.viewMain.frame.size.width, 200.0)
}
return cell
}
TableView cells have their height set by the table view.
You need to implement UITableViewDelegate tableView:heightForRowAtIndexPath:.
first, rowHeight changes the height of all rows in your table. if you want specific height for specific rows, implement tableView:heightForRowAtIndexPath: method. remove tbUpdate.rowHeight in your code first.
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var cellHeight:CGFloat = CGFloat()
if indexPath.row % 2 == 0 {
cellHeight = 20
}
else if indexPath.row % 2 != 0 {
cellHeight = 50
}
return cellHeight
}
You can try using autolayout to create a height constrait and then connect the constraint to an outlet. Then set the constant for that constraint,
var y: Float
if x==0{ //some condition
y = 10
}else if x==1{ //some condition
y = 20
}
cell.viewMainHeightConstraint.constant = y
cell.view.layoutIfNeeded()
Put this in your cellForRowAtIndexPath
Edit : I misinterpreted the question as asking for another view within the cellView, if so the delegate method heightForRowAtIndexPath is indeed correct as stated in the above answer.
An example:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
if x == 0{
return 100.0 //Choose your custom row height
} else {
return 50
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var height:CGFloat = CGFloat()
if indexPath.row == 0 {
height = 80
}
else if indexPath.row == 1 {
height = self.view.frame.size.height - 44 - 64 // 44 is a tab bar height and 64 is navigationbar height.
print(height)
}
return height
}

Hide UITableview cell

i'm trying to Hide a cell from a UITableView. just like the delete action do but i just want to hide it to later show it in the same position.
i know that UITableViewCell has a property called "Hidden" but when i hide the Cell using this property it hide but no animated and they leave a blank space
Example:
first cell
second cell
third cell
it's possible that when i hide the second cell, that third cell change position to 2 ?
thanks
One way to effectively "hide" a row with animation and without actually removing it is to set it's height to zero. You'd do so by overriding -tableView:heightForRowAtIndexPath:.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat height = 0.0;
if (isRowHidden) {
height = 0.0;
} else {
height = 44.0;
}
return height;
}
(You'd only want to return 0.0 for the specific row or rows you want to hide of course, not unconditionally).
Simply changing the return value of this method doesn't make the table view automatically adjust the row's height, to make it do so you make the following calls.
isRowHidden = YES;
[tableView beginUpdates];
[tableView endUpdates];
If you do so you'll see an animated appearance/disappearance transition between the two.
In SWIFT you need to do two things,
HIDE your cell. (because reusable cell may conflict)
Set Height of cell to ZERO.
Look at here,
HIDE cell
func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
if indexPath.row == 1 {
cell?.hidden = true
} else {
cell?.hidden = false
}
return cell
}
Set Height of cell to ZERO.
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
if(indexPath.row == 1){
rowHeight = 0.0
} else {
rowHeight = 55.0 //or whatever you like
}
return rowHeight
}
Using this you can remove reusable cell conflict issues.
You can do the same for cell?.tag also to hide specific cell by tag.
Ref: https://stackoverflow.com/a/28020367/3411787
You can't simply hide a UITableViewCell. You have to remove that cell from the table view then insert it again when you would like it to reappear in the table.
The methods you're looking for are deleteRowsAtIndexPaths:withRowAnimation: and insertRowsAtIndexPaths:withRowAnimation:. These are well documented in the UITableView documentation here. You're going to have to remember where you removed the cell from then insert it at the same position later.
Keep in mind that if you add cells to your table with a lesser row index than the row index of the deleted row, you will have to add on to the index to maintain it's relative position.
Hope this helps.
Same as Zaid Pathan but for Swift 4:
//HIDE you cell.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath) as! UITableViewCell
//hide second cell
indexPath.row == 1 ? (cell.isHidden = true): (cell.isHidden = false)
return myCell
}
//Set Height of cell to ZERO.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var rowHeight:CGFloat = 0.0
indexPath.row == 1 ? (rowHeight = 0.0): (rowHeight = 49.0)
return rowHeight
}
If you want the other cells to have a dynamic height:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 1 { // Or any other row
return 0
}
return -1.0
}
I am using Hidden in Attributes Inspector of TableViewCell -> ContentView and then implement method:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if shouldHideSection(indexPath.section) {
return 0.0
} else if let isHidden = tableView.cellForRow(at: indexPath)?.contentView.isHidden, isHidden {
return 0.0
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
You should delete row and reload table view
[tbv reloadData];
cell display, depending on the data source, so you need to deal with the data source.
if dataArr is the table view datasource,first of all, you should delete the data source where the cell,then
[dataArr removeObjectAtIndex:indexpath.row];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:#[indexpath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
at last ,you can insert data source when you should add a cell
[dataArr insertObjectAtIndex:indexpath.row];
[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:#[indexpath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
Best way to set rowHeight value in condition check
Dataarray where value stored .
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//set up here
let cell = myTableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! myCustomCell
if (dataArray?[indexPath.row].somevalue == "true")
{
cell.isHidden = true
tableview.rowHeight = 0.0
}
else{
// show cell values
tableview.rowHeight = 130
}
`
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let dicttemp : Dictionary = arrAllCoursesList[indexPath.row] as! Dictionary<String,Any>
var rowHeight:CGFloat = 0.0
if let getStatus = dicttemp["status"] as? String
{
if getStatus == "1"
{
rowHeight = 240.0
}
else
{
rowHeight = 0.0
}
}
return rowHeight
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CompetitionTableViewCell") as! CompetitionTableViewCell
let dicttemp : Dictionary = arrAllCoursesList[indexPath.row] as! Dictionary<String,Any>
if let getStatus = dicttemp["status"] as? String
{
if getStatus == "1"
{
cell.isHidden = false
}
else
{
cell.isHidden = true
}
}
cell.selectionStyle = UITableViewCellSelectionStyle.none
return cell
}

How to have one static cell in a dynamic tableview?

I would like to use a UITableView to have 2 static cells on top of a list of dynamic cells. As far as I understand, I have to use a dynamic prototype tableView. But I don't understand how to add 2 static cells and design them, eg. adding a textfield to the first and a label to the second.
What do I have to do in my storyboard? And what do I have to do inside the Controller? How can I differentiate the static from the dynamic cells?
EDIT:
I tried this for testing:
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cardCell", forIndexPath: indexPath) as CardTableViewCell
//static cell
if (indexPath.row < 2) {
cell.dyn.text = "static \(indexPath.row)"
return cell;
}
// Configure the cell...
cell.dyn.text = "buh"
return cell
}
this results in this:
Later when I use real data I will miss the first 2 data rows...
Can I somehow "reset" the row counter after I created my static cells?
And how can I modify the 2 static cells? For adding a textfield and labels? Or do I have to do this programmatically?
I found help here: Mixing static and dynamic sections in a grouped table view
And my solution looks like this:
1.
Add and layout the static cells:
Give each cell a unique name and add them as outlet to the TableViewCell class
Adjust the code:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 3
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (section == 2){ // my dynamic cell is index 2
return 5 // just for testing, add here yourrealdata.count
}
return 1 // for static content return 1
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: CardTableViewCell!
if (indexPath.section == 0) {
cell = tableView.dequeueReusableCellWithIdentifier("static1", forIndexPath: indexPath) as CardTableViewCell
cell.cardSetName?.text = self.cardSetObject["name"] as String
}else if (indexPath.section == 1) {
cell = tableView.dequeueReusableCellWithIdentifier("static2", forIndexPath: indexPath) as CardTableViewCell // just return the cell without any changes to show whats designed in storyboard
}else if (indexPath.section == 2) {
cell = tableView.dequeueReusableCellWithIdentifier("cardCell", forIndexPath: indexPath) as CardTableViewCell
cell.dyn.text = "row \(indexPath.row)" // return test rows as set in numberOfRowsInSection
}
return cell;
}
End results will look like this:
I hope I can help someone with the same question :)
you could use something like this to use or display your static cell
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return numberOfDynamicCells + 1;
}
and in you cellForRowAtIndexPath datasource you may use something like this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0){
// go ahead to display your static Cell
}
else{
//go ahead to display your dynamic cells.
}
return yourCell;
}
here is code for swift.
func numberOfRowsInSection(_ section: Int) -> Int{
return numberOfDynamicCells + 1
}
and in you cellForRowAtIndexPath datasource you may use something like this.
func cellForRowAtIndexPath(_ indexPath: NSIndexPath) -> UITableViewCell?{
if indexPath.row = 0{
// go ahead to display your static Cell
}
else{
//go ahead to display your dynamic cells.
}
return yourCell;
}
Good Luck...
Yes you can by having static cells be IBOutlet properties and in the tableView(_:cellForRowAt:) you can return those properties for any index paths you want
Here's an example:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
case 0:
return firstStaticCell
case 1:
return secondStaticCell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "DynamicCell", for: indexPath)
cell.textLabel?.text = "Dynamic \(indexPath.row + 1)"
return cell
}
}

Jerky Scrolling After Updating UITableViewCell in place with UITableViewAutomaticDimension

I am building an app that has a feed view for user-submitted posts. This view has a UITableView with a custom UITableViewCell implementation. Inside this cell, I have another UITableView for displaying comments. The gist is something like this:
Feed TableView
PostCell
Comments (TableView)
CommentCell
PostCell
Comments (TableView)
CommentCell
CommentCell
CommentCell
CommentCell
CommentCell
The initial feed will download with 3 comments for previewing, but if there are more comments, or if the user adds or deletes a comment, I want to update the PostCell in place inside of the feed table view by adding or removing CommentCells to the comments table inside of the PostCell. I am currently using the following helper to accomplish that:
// (PostCell.swift) Handle showing/hiding comments
func animateAddOrDeleteComments(startRow: Int, endRow: Int, operation: CellOperation) {
let table = self.superview?.superview as UITableView
// "table" is outer feed table
// self is the PostCell that is updating it's comments
// self.comments is UITableView for displaying comments inside of the PostCell
table.beginUpdates()
self.comments.beginUpdates()
// This function handles inserting/removing/reloading a range of comments
// so we build out an array of index paths for each row that needs updating
var indexPaths = [NSIndexPath]()
for var index = startRow; index <= endRow; index++ {
indexPaths.append(NSIndexPath(forRow: index, inSection: 0))
}
switch operation {
case .INSERT:
self.comments.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
case .DELETE:
self.comments.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
case .RELOAD:
self.comments.reloadRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
}
self.comments.endUpdates()
table.endUpdates()
// trigger a call to updateConstraints so that we can update the height constraint
// of the comments table to fit all of the comments
self.setNeedsUpdateConstraints()
}
override func updateConstraints() {
super.updateConstraints()
self.commentsHeight.constant = self.comments.sizeThatFits(UILayoutFittingCompressedSize).height
}
This accomplishes the update just fine. The post is updated in place with comments added or removed inside of the PostCell as expected. I am using auto sizing PostCells in the feed table. The comments table of the PostCell expands to show all of the comments, but the animation is a bit jerky and the table sort of scrolls up and down a dozen pixels or so while the cell update animation takes place.
The jumping during resizing is a bit annoying, but my main issue comes afterwards. Now if I scroll down in the feed, the scrolling is smooth as before, but if I scroll up above the cell I just resized after adding comments, the feed will jump backwards a few times before it reaches the top of the feed. I setup iOS8 auto sizing cells for the Feed like this:
// (FeedController.swift)
// tableView is the feed table containing PostCells
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 560
If I remove the estimatedRowHeight, the table just scrolls to the top anytime a cell height changes. I'm feeling pretty stuck on this now and as a new iOS developer, could use any tips you might have.
Here is the best solution I found to solve this kind of problem (scrolling problem + reloadRows + iOS 8 UITableViewAutomaticDimension);
It consists by keeping every heights in a dictionary and updating them (in the dictionary) as the tableView will display the cell.
You will then return the saved height in - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath method.
You should implement something like this :
Objective-C
- (void)viewDidLoad {
[super viewDidLoad];
self.heightAtIndexPath = [NSMutableDictionary new];
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSNumber *height = [self.heightAtIndexPath objectForKey:indexPath];
if(height) {
return height.floatValue;
} else {
return UITableViewAutomaticDimension;
}
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
NSNumber *height = #(cell.frame.size.height);
[self.heightAtIndexPath setObject:height forKey:indexPath];
}
Swift 3
#IBOutlet var tableView : UITableView?
var heightAtIndexPath = NSMutableDictionary()
override func viewDidLoad() {
super.viewDidLoad()
tableView?.rowHeight = UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = heightAtIndexPath.object(forKey: indexPath) as? NSNumber {
return CGFloat(height.floatValue)
} else {
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let height = NSNumber(value: Float(cell.frame.size.height))
heightAtIndexPath.setObject(height, forKey: indexPath as NSCopying)
}
We had the same problem. It comes from a bad estimation of the cell height that causes the SDK to force a bad height which will cause the jumping of cells when scrolling back up. Depending on how you built your cell, the best way to fix this is to implement the UITableViewDelegate method - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
As long as your estimation is pretty close to the real value of the cell height, this will almost cancel the jumping and jerkiness. Here's how we implemented it, you'll get the logic:
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
// This method will get your cell identifier based on your data
NSString *cellType = [self reuseIdentifierForIndexPath:indexPath];
if ([cellType isEqualToString:kFirstCellIdentifier])
return kFirstCellHeight;
else if ([cellType isEqualToString:kSecondCellIdentifier])
return kSecondCellHeight;
else if ([cellType isEqualToString:kThirdCellIdentifier])
return kThirdCellHeight;
else {
return UITableViewAutomaticDimension;
}
}
Added Swift 2 support
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// This method will get your cell identifier based on your data
let cellType = reuseIdentifierForIndexPath(indexPath)
if cellType == kFirstCellIdentifier
return kFirstCellHeight
else if cellType == kSecondCellIdentifier
return kSecondCellHeight
else if cellType == kThirdCellIdentifier
return kThirdCellHeight
else
return UITableViewAutomaticDimension
}
dosdos answer worked for me in Swift 2
Declare the ivar
var heightAtIndexPath = NSMutableDictionary()
in func viewDidLoad()
func viewDidLoad() {
.... your code
self.tableView.rowHeight = UITableViewAutomaticDimension
}
Then add the following 2 methods:
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let height = self.heightAtIndexPath.objectForKey(indexPath)
if ((height) != nil) {
return CGFloat(height!.floatValue)
} else {
return UITableViewAutomaticDimension
}
}
override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
let height = cell.frame.size.height
self.heightAtIndexPath.setObject(height, forKey: indexPath)
}
SWIFT 3:
var heightAtIndexPath = [IndexPath: CGFloat]()
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return self.heightAtIndexPath[indexPath] ?? UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
self.heightAtIndexPath[indexPath] = cell.frame.size.height
}
#dosdos solution is working fine
but there is something you should added
following #dosdos answer
Swift 3/4
#IBOutlet var tableView : UITableView!
var heightAtIndexPath = NSMutableDictionary()
override func viewDidLoad() {
super.viewDidLoad()
tableView?.rowHeight = UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = heightAtIndexPath.object(forKey: indexPath) as? NSNumber {
return CGFloat(height.floatValue)
} else {
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let height = NSNumber(value: Float(cell.frame.size.height))
heightAtIndexPath.setObject(height, forKey: indexPath as NSCopying)
}
then use this lines when ever you want , for me I use it inside textDidChange
first reload Tableview
update constraint
finally move to top Tableview
tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(CGPoint.zero, animated: true)
I was facing the same problem too. I did find a workaround, but it doesn't completely fix the jerk. But it seems to be a lot better compared to the previous choppy scrolling.
In your UITableView delegate method :cellForRowAtIndexPath:, try using the following two methods to update the constraints before returning the cell. (Swift language)
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
EDIT: You may also have to play around with the tableView.estimatedRowHeight value to get a smoother scrolling.
Following #dosdos answer.
I also found interesting to implement: tableView(tableView: didEndDisplayingCell: forRowAtIndexPath:
Specially for my code, where the cell is changing Constraints dynamically while the cell is already displayed on screen. Updating the Dictionary like this helps the second time the cell is displayed.
var heightAtIndexPath = [NSIndexPath : NSNumber]()
....
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = UITableViewAutomaticDimension
....
extension TableViewViewController: UITableViewDelegate {
//MARK: - UITableViewDelegate
func tableView(tableView: UITableView,
estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
let height = heightAtIndexPath[indexPath]
if let height = height {
return CGFloat(height)
}
else {
return UITableViewAutomaticDimension
}
}
func tableView(tableView: UITableView,
willDisplayCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath) {
let height: NSNumber = CGRectGetHeight(cell.frame)
heightAtIndexPath[indexPath] = height
}
func tableView(tableView: UITableView,
didEndDisplayingCell cell: UITableViewCell,
forRowAtIndexPath indexPath: NSIndexPath) {
let height: NSNumber = CGRectGetHeight(cell.frame)
heightAtIndexPath[indexPath] = height
}
}

UITableView's allowsMultipleSelectionDuringEditing - don't display edit circle for some cells

I am trying to delete some rows in my UITableView by setting allowsMultipleSelectionDuringEditing to YES. This is all working well; the circle is showing on the left hand side.
However, for certain cells, I don't want the circle on the left hand side to come up. How do I do that? I've tried cell.selectionStyle = UITableViewCellSelectionStyleNone during editing and that didn't work.
Any hints?
In order to disallow some rows from multiple selection you should use tableView:shouldIndentWhileEditingRowAtIndexPath: mixed with cell.selectionStyle = UITableViewCellSelectionStyleNone.
Here is an example from my code:
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath*)indexPath {
if (indexPath.row < 4) {
return YES;
} else {
return NO;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// (...) configure cell
if (indexPath.row < 4) {
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
} else {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
}
First, use these settings:
self.tableView.allowsMultipleSelectionDuringEditing = true
self.tableView.setEditing(true, animated: false)
And implement next delegate methods:
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return self.shouldAllowSelectionAt(indexPath)
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return self.shouldAllowSelectionAt(indexPath)
}
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
if self.shouldAllowSelectionAt(indexPath) {
return indexPath
}
return nil
}
shouldAllowSelectionAt is my private method which contains logic about which row to select
Have you tried to implement tableView:editingStyleForRowAtIndexPath: UITableViewDelegate's method and return UITableViewCellEditingStyleNone for cells you don't want to show delete control?

Resources