I'm seeing a weird behavior in all of my UITableView's. This is starting to drive me nuts.
I have plain styled UITableViews. The last row in the section doesn't get a separator, it just blends in to the section header (default usage by the way). Checking the height of this last row, it appears Apple is making it 1px larger to remove the separator height from the cell. The problem is when I select the row, but drag off, the separator line shows up and never goes away. If I go back a view and come back in, it defaults to off.
I'm seeing this across all of my table views, normal cells and custom cells. What can I do to make sure this last separator stays away when I cancel a selection? iOS 7 only build. Running current builds, no betas.
For me reloading of cell helped for some separator line problems:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (void)tableView:(UITableView *)tableView didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
If you change the style of the tableView in the storyboard from plain to grouped, you won't get this behavior. It will give you a section header above your section though. To get rid of it, do this -
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 0.01f;
}
Related
I have a list of custom cells in my tableview and as I scroll everything appears to fine and the cells appear to be in the same order. I have some functionality with my cells - as i select a cell (and it dynamically expands)the background color changes and a few other custom cell properties. Once I do this and then I start scrolling, different cells that i haven't even touched before show up, selected(expanded) and the cell only updates when I select it manually to the correct data. I seem to see duplicates and all kinds of craziness.
I know there are LOTS of posts about this on here so far but for me, so far nothing has worked. Would like some input on what I could do to stop this ridiculous behavior.
I have posted some code to give you a better idea of what I am doing. I know that 'dequeueReusableCellWithIdentifier' is the culprit but don't know of an alternative.
As side notes, this is a tableview(its own xib) that is a child view of a large view (also a xib). I have also already registered the nib for the tableview.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:myIndentifier forIndexPath:indexPath];
if(self.currentSelectedIndex){
if(self.previousSelectedIndex){
//collapse cell
//configure cell in method(change background color etc)
}
else{
//expand cell
//configure cell in method(change background color etc)
}
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.currentSelectedIndex = indexPath;
[tableView beginUpdates];
if(self.currentSelectedIndex){
if(self.previousSelectedIndex && (self.previousSelectedIndex != self.currentSelectedIndex)){
[tableView reloadRowsAtIndexPaths:#[self.currentSelectedIndex, self.previousSelectedIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else{
[tableView reloadRowsAtIndexPaths:#[self.currentSelectedIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
[tableView endUpdates];
if(self.previousSelectedIndex == self.currentSelectedIndex){
self.previousSelectedIndex = nil;
}
else{
self.previousSelectedIndex = self.currentSelectedIndex;
}
}
What can I do or how would i make sure that nothing else in the list 'seems' to be selected(expanded) or prevent from appearing to see duplicates as i scroll? I already keep track of my current and last selected index(as shown in the code) so I suppose that I could use that somehow?
Dequeued Cells are Reused
Know that cells are re-used, so that the appearance of a UITableViewCell is persistent for the entire life of that cell.
This means that if you do not explicitly reset all the presentation view of your cell, and just returning it unchanged in cellForRowAtIndexPath, what you are returning may be a currently selected (or deselected) cached cell.
A possible location to reset a table cell is prepareForReuse.
Design note:
How are you maintaining self.currentSelectedIndex and self.previousSelectedIndex? This is typically quite dangerous, since you are attempting to replicate the UITableView behavior. It is for example, unlikely to work with multiple selection. Setting an active selection is unlikely handle situations when the OS didDeselectRowAtIndexPath, as a result of a keyboard dismissal for example.
I am using cells with two heights based on some status.
When start is StatusAwarded it shows full cell else it will show a part of it.
Here is the code to achieve this.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
SomeClass *someClass = dataArray[indexPath.row];
if (someClass.status == StatusAwarded) {
return 252.0f;
}
return 110.0f;
}
It works all fine but when it is in edit mode, it has this issue as shown below.
I am having effect like this while editing (Deleting).
Question:
Why is this happening? How to fix this?
Note: Clip Subviews is set to YES
Try to enable Clip Subviews in Interface Builder / Storyboard.
You're not reloading the other cells, try:
[tableViewAdvancedBookings reloadRowsAtIndexPaths:[indexPathsToExpand allObjects] withRowAnimation:UITableViewRowAnimationAutomatic];
instead of:
[tableViewAdvancedBookings reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
which only reload the currect selected cell..
or maybe try reloading the whole table like:
[tableView reloadData];
and see what happen.. hope i've help, for some reason.. Good night, Cheers..
I gave a look on QuizUp and I would like to make a similar menu on my iphone application.
I don't understand how they made the menu. It looks like a table view controller, but a new menu appears under the cell when the user tap on it.
Can someone give me some clues. Is it possible to do that with the native iOS SDK ? How ?
According to the developer of Quiz Up, the app was made using Cocos2D.
That being said, it is also possible to do it using a UITableView. Theres just a couple things you would need to do. The first is get tableView:heightForRowAtIndexPath: to return a different height for the row(s) you want to be expanded. For example, if you only want one row expanded you could use the following.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[tableView indexPathForSelectedRow] isEqual:indexPath]) {
return 100.0f;
}
return 44.0f;
}
Then what you need to do is call beginUpdates and endUpdates on your tableview whenever you want the height to update.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
[tableView endUpdates];
}
After that, you just need to layout your cell so that when it's expanded, it shows the additional view and when its collapsed it should hide that view.
Trying to be ios7-esque, I am inserting a UIPickerView into a UITableView when tapping on a cell in the table. This works fine and animates nicely. However, there is an issue when I retract the cell by calling deleteRowsAtIndexPaths.
I am experiencing a "bleed"/overlap where the picker is hiding one of the cells further down in the table view. See the screenshots.
I'm not doing anything super custom, so I wonder if this is an iOS7 bug. All cells have solid background colors (white).
Any help would be greatly appreciated. Thanks!
Tapping the top row
This is mid animation when retracting. Notice the overlap and the picker bleeding out over the cell at the bottom
I'm not sure why, but it looks to me like the picker cell is covering the cell below "Choose Product". If this is indeed the case, one workaround would be to explicitly set the z-order of your cells, placing the picker cell under all others:
#import <QuartzCore/QuartzCore.h>
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = ...;// your logic for getting a cell
BOOL isPickerCell = ...;// your logic for identifying if this is the picker cell
cell.layer.zPosition = isPickerCell ? 0 : 1;
}
If the picker is near the bottom of the table, it could still show through below the last cell since there's nothing there to cover it. For example, if "Choose Product" were the last cell. You can work around this by inserting blank cell(s) at the bottom. This is a general problem with having cells of varying height.
After struggling with this problem, I realised that Apple's calendar application has the same issue
However, they minimise the side effects by inserting the row with a .fade animation.
tableView.insertRows(at: indexes, with: .fade)
I had similar issues (iOS 8, iPhone 6 simulator)
In my case, I had a custom cell containing a DatePicker being inserted/deleted either between Right Detail style cells or between a Right Detail style cell and the section footer, which worked as expected.
[self.table beginUpdates];
if (isVisible) {
[self.table insertRowsAtIndexPaths:#[index]
withRowAnimation:UITableViewRowAnimationMiddle];
} else {
[self.table deleteRowsAtIndexPaths:#[index]
withRowAnimation:UITableViewRowAnimationMiddle];
}
[self.table endUpdates];
But I also had Right Detail style cell being inserted/deleted between a Right Detail style cell and the end of section, which did not work as expected using the same code. The appearing/disappearing cell was visible on top of/through the cell above, and the cell moved twice as far as it should have. In the image below, People is appearing below Privacy, mid-animation.
However, I noticed that when the beginUpdates/endUpdates were commented out, the cell only moved about half a cell height instead of twice a cell height which meant that it looked much improved.
I also tried setting the zPosition which appeared to lessen the visibility when the cells overlapped.
// [self.table beginUpdates];
if (isVisible) {
[self.table insertRowsAtIndexPaths:#[index]
withRowAnimation:UITableViewRowAnimationMiddle];
} else {
cell = [self.table cellForRowAtIndexPath:peopleIndex];
cell.layer.zPosition = -1;
[self.table deleteRowsAtIndexPaths:#[peopleIndex]
withRowAnimation:UITableViewRowAnimationMiddle];
}
// [self.table endUpdates];
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!