How to set up a horizontal collection view w paging and a single cell centered on-screen with edges of other cells visible - ios

I haven't worked with collection views a whole lot.
A client wants a horizontal collection view set up with paging enabled.
They want a single cell centered in the collection view, with the edges of neighboring cells peeking into the view to provide a visual cue that they can swipe to see other cells.
If I set up the collection view using paging and a default flow layout, as I page over each cell ends up shifted to the left a bit more.
I implement the UICollectionViewDelegateFlowLayout protocol's collectionView(_:layout:insetForSectionAtIndex:) method, I can set up section insets such that each cell is kept centered, but when I do that the neighboring cells don't appear, and ONLY the current cell is ever visible until you start scrolling.
I assume I need to do something with a custom flow layout, but I'm not sure what, exactly. Can somebody offer some guidance?
(I'm working in Swift 2.3, although I'm "bilingual", so answers in either Swift or Objective-C are fine.)

Related

Syncing Two CollectionViews For Navigation

I’m trying to sync two collection views proportionally for navigation. One of the collection views is menu-like and is at the top, and the second is a larger one below. What I would like is for the top collection view to scroll a distance of the width of one cell (the cells are dynamically sized) when the user scrolls the bottom collection view a distance of the main screen’s width. The closest thing I've seen to this effect would be iOS: Custom top segmented control works as expected only when using debugger. What I would like to change is to have the left most cell in the top menu always selected. In addition, when the user scrolls the bottom collection view the width of the screen, a new cell should Replace the left-most cell in the upper menu and be selected. Any help in Swift would be especially appreciated, but ObjC answers are also welcome.

Complex cross layout architecture and separation of concerns

I want to implement a cross layout just like Wallapop app does on its main feed.
As you can see, it's composed of two groups of cells (Featured items, Items near you). The first group is scrolled horizontally, and the second group is scrolled vertically.
The first UIKit component that came to my mind to make that kind of layout is UICollectionView, having one section for each scrolling direction. Unfortunately UICollectionView current implementation is very limited, forcing the scroll in one direction only, no matter how many sections you declare.
So I wanted to give it a shot with vanilla UIKit components and that's what I got;
The problem with my solution is that the vertical UICollectionViewController (highlighted in green) is scrolling on its own and not pushing the horizontal UICollectionViewControllers upward.
I've also thought about using a single UICollectionViewController for the vertical cells, and setting an UIStackView with horizontal UICollectionViewControllers as needed for the horizontal cells, but it's a messy solution and doesn't scale very well, I even couldn't set a title for the vertical cells section If I opt this way.
Ideally, I want each group of scrollable cells to be it's own UIViewController in order to have a clear separation of concerns and modularity.
Is there a better way to implement a layout like the one I want with vanilla UIKit components?
The easiest and the most stable solution is to use the following view hierarchy:
Use one UICollectionView(1) instance
Horizontally scrollable sections can be implemented as Screen width UICollectionViewCell containing horizontally scrollable UICollectionView
Vertically scrollable sections should be just a regular section of UICollectionView(1)
Pros
UIKit only
Nothing extraordinary is needed - just a UICollectionViewFlowLayout everywhere
Cells are the same for Horizontally scrollable cells and Vertically scrollable cells
Good scalability and separation of concerns. Independent behaviors of Horizontal and Vertical sections each of which can have multiple data sources.
Cons
Horizontally scrollable sections should have fixed height. Otherwise scrolling behavior will be harder to maintain.
Arrow on the image means Uses!
You could use following way:
A collection view with two cell in it. First cell is for featured items and the second cell is for items near you. The first cell will cover full width and height required by your design.
For scalability use a Container View which embed a CollectionViewController which will responsible for showing featured item. This embedded CollectionViewController will scroll horizontally.
Items near you are straight forward direct cell of the initial collection view controller.
So your implementation of featured horizontal collection view remain in the embedded CollectionViewController and the items for cell remains in the primary CollectionViewController which also contain a loose connection (embedding into a container view) to the featured item.
It also does not suffer from the problem like scrolling vertically the items for sale does not scroll up the featured items.
Here is a screenshot which depicts the idea

One section of the view controller is still and one section horizontally scrollable

I would like to construct a view controller where one section of the view controller would be still and one section scrollable.
Both sections have headers where as well, one is still and one is moving along with the content in the section.
I do not want the cells in the section to be scrolled separately. All cells should move at the same time along with the header.
I have added an image to make my point little more clearer.
Use UICollection View for both view and disable scrolling for one view and enable scrolling for another view
you can probably add to your UIViewController view a UITableView on the left with fixed size (for example 150px) and vertical scroll disabled and a UICollectionView with horizontal flow and ,if needed a, with custom UICollectionViewLayout (but i think that you just need the classic UICollectionViewFlowLayout) for the right part that fits the remaining space.
Here you can find the component's documentation:
https://developer.apple.com/reference/uikit/uicollectionview
https://developer.apple.com/reference/uikit/uitableview

Is it possible to figure out what part of the cell is visible from inside the cell subclass?

In my cell subclass the user can slide the cell for actions, just like in Mail.app. However, the cells can be much larger than Mail.app, sometimes up to 1,000pt which means it requires the table to be scrolled to read fully.
This means that the normal strategy of simply centering the actions vertically in the cell will not work, as the vertical center could very well not be visible. So I want to display it in the vertical center of the visible area.
Is this possible to do within the UITableViewCell subclass where the sliding action is occurring? Figuring out where the vertical center of the visible area even is?

How should I approach structuring this view?

I'm having a hard time finding the best way to structure this design.
The top view has a minimum height and becomes sticky when it reaches this height. The bottom view hosts a paging controller with three views within. Each of these views hosts either a collection view or table view with vertical scrolling.
I'm really at a loss on how to approach this. Is the entire view scrollable and I should prevent scrolling on the second view until the top view has reached it's sticky height? Or are each of these views separate uitableviews and the pagingcontroller is just one cell? Should I even be using a pagingcontroller or should I use a scrollview with paging enabled? (the latter was a little rough interaction-wise)
Thank you!
Take a look at the Advanced User Interfaces using Collection View from WWDC this year. This view is very very very similar to the iTunes Connect app interface. The entire session video explains how they created that interface.
I used a similar method to this to create the keyboard in the Emojicate app.
I think what I'd do is actually fake the sticky header. So something like this...
Use only one collection view.
Create a "segmented data source" that contains three data sources. (See the video from WWDC about this)
When the segmented control is changed then update the collection view by changing its layout and (if you want) dataSource.
Make the entire top section a header on the collection view.
When the collection view scrolls past a certain point (when you want to sticky the header) then have a second view that is the compressed header and make it visible at the top of the screen. This is not attached to the collection view at all.
When the segmented control changes you can update the collection view by changing the "selected datasource". The datasource can also contain a UICollectionViewLayout that will update it.
Essentially, the tableview you are talking about is just a collection view where the cell width is equal to the screen width. i.e. fake a table view.
The sticky header isn't sticky at all. Just when it starts to go off screen you can put a fake header there instead.
It will require a duplicate (ish) view and some thinking about how to structure the data but I think this will be easier and less resource hungry than having multiple collection views and page controller and stuff.
If you want me to go through it in more detail let me know but it's a complex subject. Watch the video first.
I would make this part a navigation bar. Should be relatively easy. Just have to customize the back button with a barButtonItem and do a couple of labels in the titleView.
I would make the next part a Table View.
The tableView has 2 sections. The first section doesn't have a section header and the second section doesn't have any cells but just a section header.
First and only cell in this section:
And the rest would be the second section header's view:
This gives you the stickiness that you want because the section header will remain there even if you scroll past it and since the collection has only 2 sections the controls will always remain on top.
I think the collection/table paging part is the hardest part and I don't know clearly how it can be done. But I was thinking it could perhaps be a ContainerView. Each view of the container view would be either a tableview or a collectionview. You would have to add some code to handle the movement of the containerview relative to the second section header (possibly an autolayout constraint that attaches the containerview to the buttom of the first tableview that you implemented above).
I don't think having your tables/collections in a scrollview would be a good implementation. I think I have even read in documentation that developers should stay away from that (but I might be remembering it incorrectly).
I would have:
A "header view" with three subviews:
Fixed height top and bottom views (they stay visible at any size).
A middle view that appears/disappears as the superview grows/shrinks.
A scroll view (table or collection view are subclasses) on that partially covers the header view with a top inset set enough to reveal the underlying header view (the same way pull to refresh views are revealed).
The paging buttons could be set as table/collection view section header views.
Finally track the scroll view's scroll position to keep manually adjusting the header view height.
Another way to see this solution.
Two completely separated parts, a header view and a table view.
A simple header view (blue) that adjusts its subviews as its height changes. More precisely hides its middle subview (light blue) when it shrinks.
A table view that a) partially covers the header view in Interface builder but b) has a top inset as to avoid hiding the header view in the actual device (tableView.contentInset = UIEdgeInsetsMake(60.0f, 0.0f, 0.0f, 0.0f);).
The two parts are only "connected" by resizing the header view height as the table view scrolls up/down.

Resources