How do we restore the UI state of UICollectionView for current visible page, for a UIPageViewController which contains a large amount of pages? - ios

We need to build a horizontal swipe-able page, with number of page range from 2 to infinity. User has the ability to add and remove any page.
We really do not want to create all and keep all UIViewController in memory. That is highly inefficient.
We hope, UIPageViewController can have mechanism, similar to UICollectionView cell reusing mechanism.
Since I'm pretty familiar how Android handling this case. Let me describe it below
When you want to have 100 swipe-able pages, Android will only create 2 (This figure is configurable) view hierarchy. If the view is not visible, the view hierarchy will be destroyed, and a new view heirarhy for the newly visible page will be created. All the view hierarchy recreation, is done through Fragment's onCreateView (Android Fragment is similar to iOS ViewController)
When you swipe from page 1 direcly to page 4, then swipe back again to page 1, the view for page 1 will be re-created via Fragment's onCreateView. However, how does Android restore multiple UI states in the page? If there is a RecyclerView (Similar to iOS UICollectionView) in page 1 being re-created, RecyclerView's previous scroll position will be restored via onRestoreInstanceState.
In Android, the mechanism 1 & 2, is pretty much offered by the Android framework out of the box. Not much work required at developer side.
I was wondering, how does iOS able to achieve the same thing?
I have seen a technique, described in https://stackoverflow.com/a/36876103/72437
However, it isn' clear, on how the UI state restoration state work? For instance, if I have an UICollectionView in page 1. How can I restore the UI state (scroll position) of UICollectionView, when I swipe back to page 1?

Use a UICollectionView.
If you need to have controllers for each cell, load the controllers in the re-useable cell on cell initialization.
UICollectionViewCells are UIViews with reuse functionality built on top; they are only de-initialized when the UICollectionView is de-initialized. When your cell is created for the first time, also create the view controller inside (which holds the actual view you want to reuse). Use the cell reuse and configuration calls (e.g. cellForRowAt(indexPath) and prepareForReuse()) to setup your vc/view inside the cell. Dependency injection is great in this flow. Prefetch if you need to load a lot of data or have slow response times.
iOS will also optimize the number of cells being reused at a time (really should never be more than say 20, there can only be so many on the screen), so you wont have to worry about maintaining a set or tracking how many instances you have.
Use a page view indicator if you need that, or make your own.
If you want to develop your own reuse system, study that of UICollectionView(Cell) first because they do this very well imo.

Related

Advantages of tableView vs. creating UI elements in code?

I have a feature that allows users to tap the side of the screen to go through content (like instagram stories). The information is presented in different formats:
example of screen types
Currently, I am just creating UI elements (through CGRect) and placing the content on the screen according to the template type that comes in. There are many screen types and the canvas has to repaint with each switch. Should I be utilizing tableView for speed (development or otherwise)?
Repainting on condition
Is this bad practice to constantly reload and recreate items with each tap?
A table view is a vertically scrolling sequence of "cells" and has nothing in common with the situation you are describing, as far as I can see.
Actually what you are describing might be a UIPageViewController, which lets you "page" through entire screens of material and yet create each "page" dynamically according to what comes "next" in the series.
Each page would be its own view controller and could configure its own views. There would be no subviews to remove; rather, the "next" view is just sitting there waiting to be asked for. Each time the user changes the "page", the old screenful of views just goes away after sliding off the screen.

iOS screen break open closed principal

I am facing one issue, I have designed one screen which contain table cell. after some time I got new screen to be designed in which 90% cell design is same as I already implemented, but this time I don't want to make any separate custom view and reuse in already implemented table cell and new cell.
So, How can I reuse table cell in new screen without modification of existing one?
Does iOS UI element break open closed principal? or I am thinking in wrong way?
Your first option is to create a custom view that has the same design and embed that in each of your table view cells and customize the rest of the part.
Second, you can pass the state/type of the cell as per your screen requirements. Based on the state/type, you can hide/unhide the required elements.
Also, views are design components. If we modularise them well enough and keeps them separate from business logic, they won't come in way of breaking SOLID principles. Apple keeps it's logical and UI components in separate frameworks. For example, Contacts and ContactsUI.

ViewPager (Swipe-able tabs) in iOS

I'm trying to build a tabbed bar with swipe-able pages exactly similar to Android's ViewPager. Each page is supposed to hold one UITableView only.
I don't know what's the better way to achieve this but so far I have 2 ideas. Also the tabs are dynamic. I can have one tabs or 10 tabs. It depends on the API I'm communicating with. (The tabs represent shop categories and the table views represent the products)
The tabs will be a UICollectionView and then I'll use one of the following options:
First approach is to build two UIViews, each of which will hold a UITableView. One UIView will be outside the screen bounds and the other one will be the one being displayed. When the user swipes and the tabs change, the UIView being displayed will move outside the screen bounds, either to the right or left and the other UIView will be displayed. As soon as the swipe action begins, I will change UIView's (the one that's about to be displayed) datasource and reload its data.
Second approach is to have a number of ViewControllers OR UIViewContainers equal to the number of tabs (which is dynamic). I'm not sure how I'd implement this because I'd have to worry about reusing UIViewControllers/UIViewContainers inside of my main UIViewController as well as handling a large number of them.
Using one big UICollectionView to host a UITableView in each UICollectionView cell. It's pretty much the reverse of the old App Store.
UICollectionView in UITableView Tutorial
So, how do most people implement similar UIs? Is there a different approach I should consider? Any other tips that can help me implement it?
EDIT: I may have left a final detail. I actually have 2 sets of tabs (categories and sub categories). They may both be displayed, one of them, or none. It depends on the API's response. For that reason, using a 3rd party library may be hard or even impossible.
EDIT2: Added 3rd approach.

UICollectionView vs UIPageViewController

I need to have different full screen views in my app. Very similar to how snapchat works. The views should be able to communicate between each other.
My question is: Should I use a UICollectionView with cells same size as the screen or should I use UIPageViewController?
Please provide some background info to support your opinion!
I think both have pretty different purposes.
UICollectionView is great to build a mosaic of views (think an image gallery for instance), whereas UIPageViewController is kind of similar to the flipping pages of a book. The latter seems to be what you need, but UIPVC doesn't seem to offer many tweaking/customizations, like custom transitions for example. In which case you may want to start from a UIScrollView with paging enabled to recreate something similar but with more potential. Here's an example.
Personal opinion: for this specific case I'd use a page view controller. Collection views have any things you have to consider, like when the device rotates you have to recalculate where you are, which cell you have to display, ask to scroll to the current cell, and if you are displaying a video or using the camera you might have to control it perfectly, otherwise issues will come.
However think about new features that might be added to your app, if you think you might show more than 2 items on screen, then you'd better choose a collection view.
A page view controller lets the user navigate between pages of
content, where each page is managed by its own view controller object.
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIPageViewControllerClassReferenceClassRef/
So If you plan to swipe from one ViewController to another, go for PageViewController. If you plan to have only one ViewController that deal with a list of fullscreen image or so, go for a view controller with a collectionView, or maybe your own swipeView.
UIPageViewController use different view controller and load multiple controller so obvisioly take more memory as compared to UICollectionView. So if your required task is less calculation or step to do then its recommended to use UICollectionView, other case preferred way is to user UIPageController.

Is there any reason to use UICollectionView for a grid view that's completely static?

I'm making a view with a 9 x 9 grid whose cells and layout will never change or scroll. I was thinking of using UICollectionView for this but the more I look into it the more I'm finding that it's geared towards grid views that scroll and may change and reposition. Is this a good assessment? If so, am I better off sticking with my own hand-rolled grid-based view? That would at least enable me to support devices running iOS versions < 6.
I would prefer UICollectionView for grid based structure even its non scrollable. We should try to use native components and then we should customise them on need base.
Its manageable in future if you start supporting scrolling in future.
You can add functionality like cell deletion, cell addition with more precise APIs provided by Apple.
Views will be reusable.
And suppose you want support iOS < 6.0 , you can use "PSTCollectionView" which is open source library. This library checks iOS version and behaves accordingly.
https://github.com/steipete/PSTCollectionView
If the cells do not need to scroll or change, then simply having a view with 9 subviews would be perfectly acceptable. Collection views are great for when the layout changes, such as on device rotation. If you support multiple orientations, this can still be handled without a collection view.
If by static, you mean stationary, yes; and, not only for the reasons provided by the first answer. Here are some additional reasons, which I think are even stronger:
UICollectionView grid layouts accommodate orientation changes well;
UICollectionViewCell allows for better control over cell sizing based on other factors in addition to content size
UICollectionViewDatasourceDelegate simplifies connecting dynamic data to your view, and displaying updates to it
That's just three out of dozens of more reasons; for the rest of them, simply list every advantage the collection view framework provides.
The value of a collection view isn't based on scrolling at all; I say that because scrolling is not a part of the collection view framework. The collection view framework is a UIScrollViewDelegate. It is the UIScrollView class that provides scrolling.
Accordingly, all advantages that collection view provides are yours whether you choose to add scrolling or not.

Resources