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.)
Related
I have an iPad app similar to the iPad Keynote with a narrow overview on the left and a paged UICollectionView of my "slides" on the right. The collection view is using the default FlowLayout. Some of these slides are standard PDFs and some are embedded UIViewControllers that have been scaled (with a CGAffineTransform) and embedded in the cell. I'd like to smoothly animate the overview sidebar offscreen and zoom the current page cell to fullscreen. The collection view should allow paged swiping at whatever size. I'm using storyboards and autolayout.
I think I need to simultaneously animate about three things:
The collection view constraints (to the sidebar) to enlarge/shrink it
The flow layout's sizeForItemAt: value
The CGAffineTransform on the embedded view controller.
I have some pieces working (a single embedded View Controller "slide" that scales correctly) but cannot get the collectionView/cell resize dance to work correctly. The cell resize animation is jerky, or ends up with the wrong offset, or works for the leftmost cell but not for other cells.
I've tried most of the suggestions in the answers to this question but with no convincing success. I can't believe it's impossible but at this point I'm considering the smoke and mirrors approach of animating a static slide and hiding it after the animation completes. The attached video - ignoring the glitches - illustrates the kind of effect I'm after:
It's worth noting, on close inspection, that Keynote cheats somewhat when it comes to swiping between slides in edit mode, and manually manages the next slide sliding onscreen, so probably doesn't use a UICollectionView.
Has anyone done anything similar, or have any suggestions for things to try?
I managed to solve this. There's a proof-of-concept GitHub repo here.
There are a few moving parts:
There are two pieces of UIView scaling code. I suspect these could be combined with suitable delegate references as the nested view controllers are embedded. The first piece scales (statically) correctly when the Collection View cell is created. The second is an animated scale/translate when the sidebar size is changed.
I added a FlowLayout subclass to remove flicker as the collection's layout is invalidated during scaling.
The sidebar-related transform in the top-level VC uses most of the tricks in the book - invalidateLayout(), performBatchUpdates(...), layoutIfNeeded() etc. as well as animating the contentOffset to the correct value. Some manual tracking of the correct page/slide is required.
There's still a slight flicker occasionally at the start of resizing. This may not be an issue with my particular colour-scheme which will be black on dark gray. Bonus points if anyone can suggest how to track this down or alleviate it.
I have the following scenario...
When I initially load a UICollectionView, I need it to slide up from the bottom of the screen without a header. This is pretty easy.
There is an "Add" cell that takes the user through the process of adding an item. At the end of this process, we display the list again, but this time with a header. The header needs to fade in and, at the same time, the updated list slides up from the bottom.
The requirement is that the header scroll with the list after both are in place, which is pretty much the default behavior.
The problem I'm having is coming up with a workable method for animating the list slide while the header is displayed.
One thought is simply animating the height of the header. Basically, start it with a height equal to the view height, then animate it to its final size. This would automatically draw the rest of the list up, making it look as though it were sliding in.
I've tried several variations of this method with no success. I can set the height without a problem, but I haven't been able to animate it.
I had thought just returning the appropriate height from referenceSizeForHeaderInSection and reloading the data would handle it. At least that's what I gather from SO messages. I've also tried invalidating the layout and performBatchUpdates.
Would this be simpler if I placed the contents of my header in the first row of the collection view and then try animating the height of row 0?
I'm not sure which is the best strategy.
OK, I found the following which was easily adapted to my scenario...
iOS Animating UITableView Header
Here's a Wayback Machine link to the original post. It may take a little while to load. Be patient.
Wayback Machine: iOS Animating UITableView Header
And here's a GitHub link with sample code...
GitHub: MichiganLabs / AnimatingTableViewHeader
EDIT: I have create a very small app that represents perfectly the problem. https://drive.google.com/file/d/0B6sI4Feh1HJUb3pGa2pBUmY4QW8/view?usp=sharing
In the sample app, we just need to scroll down then press the button on the top bar to see the problem I am having
I am using https://github.com/jamztang/CSStickyHeaderFlowLayout to have sticky headers behaviors (like default UITableView) inside my collection view.
It works pretty well when scrolling through the collection view. I have a search bar outside the collectionview that allows users to filter the data with search text, everytime the user enters a letter, I'm refreshing the collectionview's data with the found data.
The problem is let's say there is currently 4 sections inside the collection view and that it is scrolled completely at the bottom. When I input a certian letter, it filters out everything but a single item (with a single header). The content size then changes for the collection view and displays the proper data, but then the header is too low (see screenshot).
I have investigated inside the flowlayout and inside the layoutAttributesForElementsInRect and I see it actually set the frame's origin Y to 0 (like it should be), but it seems the collectionview doesn't use this value and uses the previous one (which was when the collection view was scrolled down).
Any idea what could cause the UICollectionView to not use the desired frame inside layoutAttributesForElementsInRect ?
I tried to fix this issue, but it looks like it's impossible till UICollectionViewLayout mechanism is black box for us. Custom layout correctly returns updated frame to layout engine on reloadData:
But hidden engine not even asking attributes if they are equal. In your case you can use simple workaround. Just update contentOffset after reload.:
[self.collectionView reloadData];
self.collectionView.contentOffset = CGPointZero;
I have a screen in my app that consists of a UITableView with another opaque view overhanging on the top (which is also interactive). The content offset is set correctly such that the entire tableView is visible to a sighted user.
However, when using VoiceOver and paging up/down with three fingers the default scroll distance will place part of the tableView under the overhanging view, and thus prevent VoiceOver from reading part of the tableView[1].
Is there any way to change how tall a "page" is when using VoiceOver?
[1]: I know that there are still ways to cycle through all the elements, etc, but it's far easier and more discoverable for partially sighted users to skim over elements with their finger.
I think you are looking for this: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIAccessibilityAction_Protocol/index.html#//apple_ref/occ/instm/NSObject/accessibilityScroll:
Re implement that method and scroll the amount of pixels you require instead of a whole page
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