I'm using [beginUpdated] to expand and collapse cells in my tableview. Works as expected however there is a side effect. The top border of the selected cell disappears. To repro make a tableview with selection style none. Use the code below you will see that selecting a row makes the border disappear. Any suggestions? I've tried unsetting separator style and resetting to singleLine. I've tried layoutIfNeeded.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[tableView endUpdates];
}
This seems to be core SDK error because I reproduced in a new project with nothing but the code above and cell selection style of none.
Any work arounds? Using a 1 px UIView as a pseudo border is not an option because comps call for a group style look and figuring out if a reuseable cell should have inset or full border for every cell is just not practical.
I solved this by deselecting the cell after the updates.
Objective-C:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath
{
[tableView beginUpdates];
[tableView endUpdates];
[tableView delesectRowAtIndexPath:indexPath]
}
Swift:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableview.beginUpdates()
tableview.endUpdates()
tableview.deselectRowAtIndexPath(indexPath, animated: true)
}
Related
I try to make cells expand/collapse with drop-down like animation, so when table view recalculates height it moves down other cells below the one that was tapped,
but if the tapped cell top margin is not entirely visible, table view changes its height update behavior by moving all above cells up:
http://imgur.com/CldzuFf
Is there a way to make cells expand with top-to-bottom behavior always?
Reloading cells like this:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:arrayToReload withRowAnimation:UITableViewRowAnimationBottom];
[self.tableView endUpdates];
Just set the contentOffset based on selected row
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell * theCell = (UITableViewCell *)[tableView
cellForRowAtIndexPath:indexPath];
CGPoint tableViewCenter = [tableView contentOffset];
tableViewCenter.y += myTable.frame.size.height/2;
[tableView setContentOffset:CGPointMake(0,theCell.center.y-65) animated:YES]; // need to customize the y offset 65 to your value
// reload row here
}
I've been banging my head on this problem for hours, but every time I try something like this:
self.dataArray.append(newCellObj)
and then I do this:
self.tableView.beginUpdates()
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Top)
self.tableView.endUpdates()
The UITableView will automatically scroll to the top of the page.
Even if I try:
self.tableView.scrollEnabled = false
self.tableView.beginUpdates()
self.tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Top)
self.tableView.endUpdates()
The UITableView will still scroll to the top even with scrolling completely disabled. What exactly causes the ScrollView to scroll to the top after insertRowsAtIndexPaths is called?
The only solution I have for this issue is to use this:
self.tableView.reloadData()
instead. If I use reloadData instead than it's fine, but then I lose the nice animation which I'd really like to keep.
I also have self.tableView.scrollsToTop = false and I've tried many other configurations like that that could disable scrolling somehow, but, there's something that overrides this after insertRowsAtIndexPaths
I was encountering the same issue as OP. Additionaly, sometimes some of my table view cells would go "blank" and disappear altogether, which led me to this related question.
For me, the solution was to do ONE of the following:
implement func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
disable auto layout
set a more accurate estimatedRowHeight on my UITableView
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
// I'm use auto layout and this variant without animation works
// ...insert object to datasource
NSUInteger idx = [datasource indexOfObject:myNewObject];
if ( NSNotFound != idx )
{
NSIndexPath *path = [NSIndexPath indexPathForRow:idx inSection:0];
[self.table beginUpdates];
[self.table insertRowsAtIndexPaths:#[path]
withRowAnimation:UITableViewRowAnimationNone];
[self.table endUpdates];
[self.table scrollToRowAtIndexPath:path
atScrollPosition:UITableViewScrollPositionBottom
animated:NO];
}
So basically what I am doing now is expanding my cells by selecting on them and using heightForRowAtIndexPath to change their height and if I select on it again or select a different cell those cells will expand or go back to their normal size.
However, upon the cell expanding I have some extra data to show in the expanded section, change the background color of the cell and set some other properties that I have defined in my tableviewcell subclass. So as an example when the cell is in its normal height the background will be light green. When its expanded it needs to be white. I set my tableviewcell subclass property (a BOOL) so that when its time to loop through the cells again (cellforRowatindexpath) i can update these properties as needed. Unfortunately, I haven't been able to find a way to get the current cell thats been selected in cellForRowAtIndexPath.
Here is the relevant code below. Keep in mind that I want to keep track of the current cell selected and the previous cell (if different from the current one) so that i can update both cells properties. Only one cell can be expanded at a time. When the current cell is selected and expanded the previous one(if applicable) will contract back to normal height. My configureCell method is just there to assign the properties based its BOOL property.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:myIdentifier forIndexPath:indexPath];
[cell configureCell:self.item[indexPath.row] isCollapsed:cell.isCollapsed];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *currentCell;
MyCustomCell *previousCell;
self.currentSelectedIndex = indexPath;
//assign previous and current if previous is nil
if(!self.previousSelectedIndex){
self.previousSelectedIndex = self.currentSelectedIndex;
currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
currentCell.isCollapsed = NO;
}
//we have tapped the same cell as before
else if(self.previousSelectedIndex == self.currentSelectedIndex){
previousCell = [tableView cellForRowAtIndexPath:self.previousSelectedIndex];
previousCell.isCollapsed = YES;
self.previousSelectedIndex = self.currentSelectedIndex = nil;
}
//if they aren't equal, then collapse the previous selected cell
//and expand the current selected cell
else{
previousCell = [tableView cellForRowAtIndexPath:self.previousSelectedIndex];
previousCell.isCollapsed = YES;
currentCell = [tableView cellForRowAtIndexPath:self.currentSelectedIndex];
currentCell.isCollapsed = NO;
self.previousSelectedIndex = self.currentSelectedIndex;
}
[tableView beginUpdates];
if(self.currentSelectedIndex){
[tableView reloadRowsAtIndexPaths:#[self.currentSelectedIndex, self.previousSelectedIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
}
[tableView endUpdates];
}
So, obviously my current and previous cell will be trashed once we leave this method since they are local but I am struggling with how to:
a. reload the cells which would cause cellForRowAtIndexPath to execute again(this works when trying to use reloadRows - but maybe I'm doing that wrong)
b.once cellForRowAtIndex starts going through the cells how to capture the currentCell and the previousCell so that i can update its content as I described above. [dequeueReusableCellWithIdentifier:myIdentifier] just gets a new cell which I do not want obviously.
The cells expand and contract fine so thats not an issue.
I have a UITableView configured as 'UITableViewStylePlain' with UITableViewCellSeparatorStyleSingleLine for its separator style. The cells have a background color.
The problem is that when you scroll the tableview, once some cells disappear off screen and are brought back, the separator is no longer visible.
The cells are registered with:
[tableView registerNib:nib forCellReuseIdentifier:cellIdentifier];
Cell code:
- (void)customizeMyTable
{
[self.tableView setDataSource:self];
[self.tableView setDelegate:self];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
NSString *cellIdentifier = [MyTableViewCell cellIdentifier];
UINib *nib = [UINib nibWithNibName:cellIdentifier bundle:nil];
[self.tableView registerNib:nib forCellReuseIdentifier:cellIdentifier];
self.tableView.rowHeight = 50;
}
- (UITableViewCell *)tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyTableViewCell *cell = (MyTableViewCell*)[tableView dequeueReusableCellWithIdentifier:cellID];
[cell configure:someDataForThisRow];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = [UIColor lightGrayColor];
}
Anyone experience this problem? This seems to happen only on iOS 5, not on iOS 6 Tableviews.
If you implemented layoutSubviews in your custom cell, and you accidentally forget to call the corresponding super method, you will not see the separator line.
Maybe you should check to see if you forget to call super in your other methods.
- (void)layoutSubviews
{
[super layoutSubviews]; //<-THIS LINE YOU NEED
//own code continues here
}
I've had to set the separator insets to 0 to stop the problem.
My problem also got solved by setting separator insets value 0.
If you build content of your UITableViewCell dynamically, please be sure that you add your subviews to contentView not to self:
contentView.addSubview(subView)
instead of
self.addSubview(subView)
It is related to LED screen resolution, since actual devices has very high resolution, the Monitor finds it hard to render those minute lines on the screen. It will work fine on actual device.
someone told me not to care of it. so you are fine with this if problem is only with simulator.
If its annoying to you then make a custom cell and put a separator into that and also remove the default separator from the cell by
For Obj.C:
[self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
Otherwise you should be fine when you will test on real device.
I have the same problem in swif. In my case, I found that the cells newly appear while scrolling overlap the others a little bit by clicking "debug by View Hierarchy" button. That's why separator lines disappear.
So the solution is quite simple, set the cell return in cellForRowAtIndexPath clipsToBounds = true so that it would not go out of the height you assigned and overlap the other cell's separator line.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellView = tableView.dequeueReusableCell(withIdentifier: cellReuseId, for: indexPath)
cellView.clipsToBounds = true //Add this line
return cellView
}
I have a custom tableFooterView (it's just an 8px high CoreGraphics arc with a gradient) that I set with the tableFooterView property in viewDidLoad rather than viewForFooterInSection. When setting it with viewForFooterInSection, it floated over the content when it reached the bottom, whereas tableFooterView does what I want it to in that it stays with the UITableView's height.
But when the cells or table view do change in height, the tableFooterView animates to them slowly (about half a second but it's very noticeable). This is pretty awkward since the footer is supposed to look like an extension of the last cell. For instance, when heightForRowAtIndexPath changes the height of a cell, the tableFooterView kind of ghost-floats back. In this screenshot the bottom cell has just been shrunken to its normal size and the footer is floating back.
(As a new user I can't post images but here's the link: http://desmond.imageshack.us/Himg835/scaled.php?server=835&filename=iossimulatorscreenshotj.png&res=landing)
(This content is no longer available, 14/9/15).
It will also float over the content when the height of the last cell is suddenly changed to be larger than it was.
Any pointers? Thanks very much.
Edit: By cells changing in height, I mean through the heightForRowAtIndexPath section:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
Note *currentNote = [self.notes objectAtIndex:indexPath.row];
if (currentNote.associatedCellIsSelected) {
return NORMAL_CELL_FINISHING_HEIGHT*2;
}
return NORMAL_CELL_FINISHING_HEIGHT;
}
Edit 2: In didSelectRowAtIndexPath I make the cell selected (actually the cell's note), begin / end updates as well as call reloadRow for the row that's been selected.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Note *currentNote = [self.notes objectAtIndex:indexPath.row];
if (currentNote.associatedCellIsSelected == FALSE) {
currentNote.associatedCellIsSelected = TRUE;
[tableView beginUpdates];
[tableView endUpdates];
}
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; }
I've also made sure that I get the same behavior with a plain rect redColor UIView in place of the Core Graphics footer, with the same results. I wish there was just an easy way to override the footer and tell it to not animate!