UITableViewController or UIViewController when adding additional controls - ios

I have a number of views that include tableviews, but other controls as well. Up till now I have been subclassing UIViewController and manually adding a tableview to it (with my other controls above/below it). Not too much hassle, other than having to manually handle the scrolling, and sometimes some resizing (if the table's content is dynamic).
I only just found that the tableHeaderView and tableFooterView of a UITableView can pretty much handle anything you throw at them. I guess I skimmed them previously, thinking they were related to section headers/footers when they are of course not related at all.
So with that in mind, and before I convert a bunch of classes over to subclass UITableViewController instead of UIViewController, is this standard practice? If I have a view, for example, that is mostly non-table content but with a dynamic tableview half way down, is it a good idea simply to use a UITableViewController and put everything around it in the header/footer?

The table view header and footer are scrolled with the table view's content. If you need them to always be visible, your current approach is the best. If you don't mind the header views being scrolled, you can indeed refactor your app.

A UIViewController manages a view hierarchy. If your view contains significant non-UITableView content, I would manage the view hierarchy with aUIViewController and include the UITableView as a subview in the view controller's view property.

Related

Two UIViews & one UICollectionView inside UIScrollView (or better approach)

I need to have iOS app with screen like this:
screen
The idea is when user start to scroll down the first UIView to move up until the second UIView reach the top where it will stick and only UICollectionView will continue to move up.
Currently I'm using this structure
UIScrollView (main scroll)
UIView (some banners)
UIView (UISegmentedControl)
UICollectionView (grid with items, scroll is disabled, main scroll is used)
I manage to do it, but I needed to set UICollectionView height constraint manually in the code (calculated based on all items in grid) in order to appear in UIScrollView (everything else is handled by AutoLayout in Storyboard). The problem with this is that UICollectionView think all cells are visible and load them, so the whole recycling & reusing thing does not work. It's even worst because I use willDisplayCell method on UICollectionView to load more data when last cell is displayed, but now it load all pages at once.
My question (actually they are 2)
How can I fix the issue above?
What is the right way to achieve this functionality? Maybe my whole approach is conceptually wrong?
Collection view is a scroll view itself. So maybe you could have same functionality only with Collection view with sections or even custom layout?

What's the best way to build a very flexible/dynamic "header" in UICollectionView

I need to build a UICollectionView with a UICollectionViewFlowLayout and a very dynamic "header" (for clarity, I'll call it "view A" to avoid mixing it with a true collection view header) but I'm not sure about what can be the best way to do that: collectionViewCell, header or supplementary view?
What I mean by flexible, the bullet point being ordered by decreasing importance:
View A will contain buttons and subviews that need to detect gestures so I must be able to detect actions on subviews of view A.
I need to be able to reload data on the collection view without reloading view A.
I need to be able to update the layout of subviews of view A whenever I want (on viewDidScroll of the collection view delegate for example, update according to contentOffset changes).
If possible, I'd like to be able to change the frame of view A dynamically (I mean without having to invalidate the layout). I would like view A to be sticky at the top and shrink while scrolling until it disappear. Have a look at recently launched "Secret" app to see what I mean (done on UITableView for them). Though I could just scroll without changing the frame and cheat by changing the layout of subviews (see point 3) in order to give the sensation of a sticky header.
What do you think is the best component to do that? Can I use a UICollectionViewCell, a header or a supplementary view? If so which one? If not, do you think of an alternative way I could use to have the same behavior (transparent header and view A behind the collection view? adding view A somewhere else, where, in the view hierarchy?).
Thanks for your help!
Take a look at the UICollectionReusableView class.
You can register your nib on the CollectionView as "SupplementaryView" (registerNib:forSupplementaryViewOfKind:withReuseIdentifier:, use the UICollectionElementKindSectionHeader kind of view)
then you have to implement the collectionView:viewForSupplementaryElementOfKind:atIndexPath: method in your delegate and make sure to return something for the UICollectionElementKindSectionHeader kind.
and finally you have to implement the collectionView:layout:referenceSizeForHeaderInSection: method of your UICollectionViewDelegateFlowLayout to set the size of your header.
Let me know if it help.

How would I create an "About" page like this for my app? How do I have a UITableView (grouped) under a UIView?

Take this about page for Things:
I'm having trouble creating something similar. I just want a UITableView under a UIView with a UIImageView and a UILabel in it.
If I use a UIViewController and so I can position the UITableView downward, I get this error: "Static table views are only valid when embedded in UITableViewController instances."
If I use a UITableViewController with a grouped style and use contentInset on self.tableView to move it down ([self.tableView setContentInset:UIEdgeInsetsMake(150,0,0,0)];) I can't figure out how to place a view above it. If I try to attach anything to self.view it crashes (obviously). Same happens if I attach anything to self.tableView.
I then tried making the UIView the header of my UITableView section (I only need one section) but I can't get it to move up enough. It just sits inside the UITableView almost.
How do I have a UITableView (grouped style) exist with a UIView above it?
This can be achieved easily using the tableHeaderView property of UITableView. If you are using Interface Builder (which it looks like you are), then you can just drag a UIView above the table view and it will be set as the table's header view. All you need is a UITableViewController; no need for UIViewController and manually laying it out.
That's because the view probably isn't placed on top of the table but rather within the table's section 0 header. Or, even more likely, the view in question is just a regular UITableViewCell with a 0 alpha background.
Either of these options would allow the top view to be scrolled out of frame as the user scrolls under every condition.
I recommend [MDAboutController] (https://github.com/mochidev/MDAboutController)
It's easy to integrate and you don't have to waste any time configuring the UITableView.

iOS prevent subview of tableview from scrolling with tableview

I have added a subview to my tableview and when ever the user scrolls the tableview, the subview scrolls with it. How do I prevent this? I know it's probably along the lines of not adding the view to the tableview's subviews, but I have no knowledge of any other ways to do this. Thanks.
If you want to make a view a subview of the table view, then you can make it floating (non-scrolling) by changing its origin.y value in the scrollViewDidScroll method.
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
self.iv.frame = CGRectMake(self.ivOrigin.x, self.ivOrigin.y + self.tableView.bounds.origin.y, self.iv.frame.size.width, self.iv.frame.size.height);
}
In this example, "iv" is a property for an image view, and "ivOrigin" is a property for the initial origin of the image view (defined when I created the image view and its frame in viewDidLoad).
The UITableView is built and intended to be a view of things that scroll.
So, you can either fight that, which as you're discovering is quite hard since everything about the component is built and focused around scrolling and fast display of a subset of the full list data... Or, you can not fight it and put your static item on top of the table as a fixed-position item.
If there's a reason you can't add the table view and your animate-out item in your main view, you can always add a custom UIView class that contains both the table view and your animated view. Have your custom view class expose the contained table view as a .table property, and the container you're putting things in can be tweaked to use "mycontainerObject.tableview" instead of just "tableview" where needed.
Yes, it's a little more work to write the custom UIView subclass and give it a couple properties to hold the UITableView and whatever UIView you're animating out.. but it's likely a lot safer in the long run than trying to "hack" into the UITableView's methods and view hierarchy to try to give it a "fixed in place" behavior.

UITableView will not resize after UITextField becomes first responder

I have two Scenes in my Storyboard that are nearly identical. Both are UITableViewControllers. Both have header and footer views. The header views have a UISearchBar and the footer views have a UIView that contains a UITextField. Each have only one prototype cell. One is prototyped as a "Basic" cell and the other is prototyped as "Right Detail" cell.
Here's the problem. When I click the UITextField in the footer view on the first scene, the table resizes automatically so that the bottom of the table is at the top of the keyboard. This allows me to scroll the table up so the footer view shows and the user is able to see what they're typing. The other scene will not automatically resize the UITableView so the UITableView cannot scroll the footer view to where it can be seen and the UITextField is hidden under the keyboard. I can't even manually scroll the table far enough since the footer is always at the bottom of the UITableView.
A little added info. The scene that works has many rows of data while the one that doesn't work only has a couple. I tried adding a number of rows until the table had enough to enable scrolling and it doesn't fix the problem.
I have checked everything I can think of and I can't see anything that would allow one of the views to let the UITableView to automatically resize to work with the keyboard and the other not. I must have overlooked something but I can't seem to find it.
Any help will be greatly appreciated!
Rob
I thought this problem was caused by copy-and-pasting from one view to another, but I had the same problem once I'd (in theory) fixed it.
The answer for me turned out to be simple: I hadn't called [super viewWillAppear:animated] in my UITableViewController subclass' viewWillAppear: implementation. Make sure you've got a call to the superclass' method and hopefully the problem will go away.
I am guessing the frame of the tableview is not being resized to the smaller size in the second case.
Print out the frame and content sizes in both the cases once its loaded, that should help you see if there is an issue.

Resources