UITableView negative top content inset causes glitch when reordering rows - ios

I have a UITableView with a negative top content inset (-20). I use the negative inset for a shadow effect: The table header is a shadow gradient. The negative inset causes the shadow to only appear when the user is dragging the table down (similar to the Alarms table in the Clock app).
This works fine. Until I start reordering the rows (by standard UITableView reordering mechanism).
The instant I grab the first row, the whole table jumps down, so that the bottom edge of the last row is aligned to the bottom of the screen. This is a really weird glitch. When I release the row (at the same or some other position), the table stays in this strange, misaligned state. When I do some scrolling, the table returns to its original position.
This also happens for the other rows if I drag them to the top row. Reordering below the top row works fine. When I change the content inset to zero (or a positive number), the glitch does not occur.
It really seems like a bug in iOS (5.0) - unless I am missing something? Any idea how to work around this?

I'm also experiencing this exact issue in iOS 6.
I couldn't find a fix, but there's a workaround which might work if your table only has a single section. Basically, instead of setting the content inset to a negative value, you can set a negative section header height. This seems to have the same effect as the negative inset -- nudging the entire contents of the scroll area up -- without the glitches during reordering.
So instead of:
[tableView setContentInset:UIEdgeInsetsMake(-16, 0, 0, 0)];
Try:
[tableView setSectionHeaderHeight:-16.0];
This of course won't play well if you have content in section headers (or multiple sections in your table), but for single-section tables it seems to be a passable workaround.
One quick update since I don't have enough rep to comment yet:
The original bug this is trying to work-around appears to be fixed on iOS 7. I wound up wrapping my fix in a version-checking conditional for iOS <7 devices.

Related

How to tell the UITableView to bounce into place programatically?

My goal is pretty straightforward:
The user should be able to move cells in the UITableView up and down by using the provided buttons. I want the new selected cell to appear exactly where the old selected cell was with the exception of the scrolling being at the the beginning of end of the tableview.
I tried using
[table selectRowAtIndexPath:newIndexPath animated:false scrollPosition:UITableViewScrollPositionMiddle];
But the problem is that the row is always moved to the same position near the center of the screen which I don't want.
I want to center the
table.contentOffset.y
exactly where I am programmatically placing it. However, when I set this with
[table setContentOffset:CGPointMake(0, newVerticalContentOffset)];
so I did exactly that. Now I have the problem of the scrolling going way outside the the table and even the normal bounce range. The only way to get it to 'bounce' back is if the user scroll touches the list.
I also tried programmatically setting the offset to the 'min' and 'max' of it happened to go out of those bounds. However, I realized that this was complicated because I have to add the height of the navigation bar and the status bar to get the top coordinates and get the content size to determine the bottom. I think it would be easier if there was simply a way to programmatically 'bounce' or 'release' the tableview back into place. I tried calling the table's delegate with flags like
scrollViewDidScroll
This crashes my application. I realized that even if I did perform one of these last two solutions, that the action would still not represent my goal. If I move a cell down from the top, the view scrolls with it. I do not want that to happen because it is very close to the top. In this case, I wouldn't mind it making its way to the middle before scrolling the view.
The best idea I have so far is somehow attempting to center scroll the cell and if it is able to be centered (meaning it is not near the top or bottom), not to actually center it.
I thought about performing a centering then checking if the y coordinate changed by exactly 1 cell and leaving it if it did, otherwise using the old position. However, I imagine that the user may be somewhere near the middle of the list and happens to be exactly 1 cell away from the middle. When he moves the cell, it will move 'unexpectedly' which is not what I want.

iOS: Tableview with custom cells does not scroll

I'm using a nav bar orchestrated set of tableviewcontrollers to display a hierarchy of data. The bottom level of data is displayed in a custom tableviewcell, which has its content described in a xib, and results in a required cell height larger than the default. I posted another question on how to programmatically extract the resulting cell height, but no usable answers, so I now implement heightForRowAtIndexpath to return a hardcoded value that is the height in the xib attributes panel. But, when the table is displayed with more rows than can fit in the normal display size (480h,320w), the bottom row is chopped off as expected, but I can't scroll it to see the rest of the row. I've searched rather extensively, but nothing has helped. I poked at various attributes (tableview sizes, scrollingEnabled, etc.) but they all seem as expected values (e.g., scrollingEnabled is true). One post suggested that no scrolling would occur unless the contentSize was larger then the frame, so I looked at those values, and it sounds promising, in that my frame size is a typical 460h x 320w, but, my contentSize is 0 x 0! Further searching (e.g., "setting contentSize" or "contentSize is 0") didn't clear anything up. I thought contentSize was computed for free from the table row count and their heights, so how could I be getting 0? Even going back to allowing a default row height by not implementing heightForRowAtIndexpath still resulted in a 0 contentSize. Some searches suggest turning off autoLayout for the custom table cell, but still the same. So, what might be going awry? Thanks for any thoughts or guidance.
Update: Sorry, I confess! I had originally been developing on a mac mini with a regular USB mouse, where scrolling in the simulator was left button down and drag. I recently switched to an iMac with the magic mouse. I'm now so used to just dragging my finger on the mouse to scroll code, web pages, etc., that I didn't think to try clicking and holding the left mouse "button", and then dragging the mouse. When I did, everything worked as expected. I had really thought things were hopeless when any similar variables/values in the app on the mini were equal to those on the iMac, but it was just me getting tricked by fancy technology. Sorry for the distraction.
set your tableView's frame and your cell's frame correct,and implement
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath in your UITableView to give a right height. If that doesn't work try set your tableView.autoresizingMask to UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
which can help you with the size of the tableview
I had a similar problem. My tableView would't scroll when the content exceeded the tableViews frame.
The problem for me was that I had "Use Autolayout" checked but no constrains on the tableView. Adding vertical and horizontal space constrains on the tableView fixed my problem

UICollectionView animating reusable cells?

I've got a UICollectionView that is formatted as a single, horizontally scrollable row across the screen. It represents the next-up entries in a queue, so whenever items are added and deleted, it always happens at Index 0 (the far left of the View) and then the whole thing moves forward or back by one space. It's super-simple in the code, just:
[_collectionviewNextUp insertItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]];
and
[_collectionviewNextUp deleteItemsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]]];
Everything is working properly, except the animations for insertItemsAtIndexPaths: and deleteItemsAtIndexPaths:, specifically when the CollectionView items extend beyond the edge of the screen. As long as there are only 6 items in the queue (the number that can be seen at once), it animates perfectly; but 7 items or more and the animation gets weird. Delete an item (from the left) and it also animates one being added to the right; add an item (on the left) and it also animates one being deleted from the right. Even if the queue is 50 items long, it always animates item #6 (the last visible one onscreen) disappearing and reappearing. There are no errors or warnings or anything, and I'm left with the correct number of items in the View after the animation is over, it just animates a cell being added/deleted at the edge of the screen.
My theory is that the reusable cells are being animated. Does that sound like it could be a thing? Scrolling left and right works perfectly, but inserting and deleting seems to only animate in pairs, and they always "fly in" and "fly out" in the same direction, as though one is taking the other's place. It looks (to my inexperienced eye) like the cell on the end is being flown over and added to the front, or the one on the front is being moved over to the end.
I've tried to do research on this but all I can find are animation problems that throw errors and exceptions, which mine doesn't do. Has anyone else experienced this? And can anyone offer a fix, wherein the Index 0 item gets animated and the rest just smoothly slide onto and off of the screen?
I assume you're using flow layout. Flow layout is very buggy animating items across the layoutAttributesForElementsInRect: boundary (i.e. items moving in and out of view). In my experience, you can fix some of these issues by overriding the 'initialLayoutAttributesForAppearingItem' & finalLayoutAttributesForDisappearingItemAtIndexPath: methods and correcting the frames when the super class returns incorrect values. Here is a successful answer to a very similar issue.
I open sourced a simple uniform grid layout VCollectionViewGridLayout that greatly improves animations over what UICollectionViewFlowLayout provides. However, it currently only does vertical scrolling. But if you went in there and transposed all of the horizontal and vertical calculations, I'm sure it would solve your issue.

TVirtualTreeView with rows of variable height: scrolling artefacts

I am using the VirtualTreeView together with the OnMeasureItem event to display rows of variable size. The problem is that the event seems to be called only if a row is painted (following the virtual paradigm). But this leads to the scrollbar being displayed incorrectly. If I scroll to the bottom (by dragging the scrollbox with the mouse, not clicking the scroll buttons at the top or bottom), not the last row is displayed (which is what I would expect), but some row in the middle. After that, the scrollbar is updated and I can scroll further down. It seems as if the component uses the DefaultNodeHeight for its scrolling calculations. But since my rows have variable height, I cannot specify a DefaultNodeHeight that would lead to correct results. Option toVariableNodeHeight is enabled.
Has anyone experienced this before and maybe found a workaround? Or am I doing it wrong?
You need to set DefaultNodeHeight to the maximum value you will be using and OnMeasureItem event set custom height value for the current node. Similar issue was described here.

Strange behavior with horizontal scrolling UITableView (in Monotouch)

We have a UITableView that we have configured to act like a Grid, allowing both horizontal and vertical scrolling. We accomplish this by dynamically changing the ContentSize in a custom UITableView's LayoutSubviews method, which helps with autorotation, scrolling, etc.
Everything works as expected except on a couple of our larger grids. When these grids are scrolled horizontally (swipe left), as soon as the ContentOffset.X is greater than or equal to the Bounds.Width, the table view disappears. It is still present and receives input, but nothing is painted. On swiping back to the right, as soon as the width threshold is crossed, everything is repainted.
In situations where the size of the grid is less than half of the configured UITableView width, this issue does not occur. We cannot change the size of the grids because they are configured by customers in the field who expect the data to be available.
I have checked and/or removed as much of our custom drawing code as possible and the issue is still occurring. Does anyone have any ideas?
That is because although the UITableView inherits from the UIScrollView, it is only meant to have a single column, hence it draws its cells according to its Bounds.
If you want to create a grid-like control with the UITableView, I suggest using multiple table views in a parent UIScrollView side-byside and change that one's ContentSize.
I came across this same issue and posted a bug report (10561166) back in December on the Apple Developer site.
I received a response today from Apple in which they stated that
UITableView is not designed or intended for horizontal scrolling.
(I had since changed my design not to require the horizontal scrolling.)

Resources