How to jump to a particular page with UIPageViewController? - ios

I'm using Xcode 8's default Page-based application, and I'm stuck trying to jump to a particular page (as opposed to swiping left and right to turn). I have found similar questions on StackOverflow, but the answers mostly suggested using this method:
setViewControllers:direction:animated:completion
I don't need to change the number of pages to be displayed, so can I avoid using setViewControllers?
After reading through Xcode's page-based application template, I think this function may work:
func viewControllerAtIndex(_ index: Int, storyboard: UIStoryboard) -> DataViewController?
However, I don't know where to get the parameter storyboard: UIStoryboard, since ModelController (the controller that serves as UIPageViewControllerDataSource) isn't part of the storyboard.

The view controllers passed to this method are those that will be visible after the animation has completed. Use a data source to provide additional view controllers to which users navigate.
When defining a page view controller interface, you can provide the content view controllers one at a time (or two at a time, depending upon the spine position and double-sided state) or as-needed using a data source. When providing content view controllers one at a time, you use the
setViewControllers(_:direction:animated:completion:)
method to set the current content view controllers. To support gesture-based navigation, you must provide your view controllers using a data source object.
The data source for a page view controller is responsible for providing the content view controllers on demand and must conform to the
UIPageViewControllerDataSource
protocol.
The delegate object—an object that conforms to the
UIPageViewControllerDelegate
protocol—provides some appearance-related information and receives notifications about gesture-initiated transitions.
setViewControllers([<#Your ViewControllers#>], direction: .forward, animated: true, completion: nil)
More Info
Apple Docs
Stackoverflow

Related

How to manage multi-view apps without segues

I'm working on an app that has about 5-6 different views with inputs and buttons within each view. The user does not necessarily proceed through the views in a set order. One of the views has quite a bit of custom user interaction that subsequently builds out a visual list of text fields and labels. I need the user to be able to leave that view and then return at a later point with the constructed visual in tact.
To avoid having a monolithic view controller, I have each view corresponding to its own view controller and storyboard. As a result, the only main way I can find to navigate between them is via segues. The problem is that, after I dismiss a segue, any interactions or view updates for that view controller are lost when I return to it.
Some of the views only have inputs like a couple text fields but the one view can have upwards of 100+ mixed inputs depending on user interaction. Rather than trying to pass that data around when dismissing and then eventually reload and reconstruct the view, I'm hoping to find a way to hide and show view controllers without losing the visual updates within their views.
Is this possible at all?
Let me know if I'm being too vague and I can try to provide more detail.
Thanks in advance!
You don't have to use segues to display view controllers from storyboards.
You can just load the storyboard, instantiate the view controller and then use it (push or present it or even set it as the key window's root view controller). It's no problem:
// Suppose you have a 'Signup.storyboard' that has an initial viewController defined:
let signupStoryboard = UIStoryboard(name: "Signup", bundle: nil)
if let signupViewController = signupStoryboard.instantiateInitialViewController() {
present(signupViewController, animated: true, completion: nil)
}
If the view controller you want to load is not the initial one, make sure you define a storyboard identifier for it (in the storyboard, e.g. identifier="signup"). Then use:
let signupViewController = signupStoryboard.instantiateViewController(identifier: "signup")
The view controller will be loaded from the respective storyboard and you can use it just as any other view controller.
You can even keep strong references to the controllers and re-use them again after other view controllers were visible in between.
For each of the view controller you need to manage its data source and update in as user changes data in UI. Also you have to store the datasource somewhere i.e. in database, userdefault ,core data etc.
And if user again pushes any view controller load the data from its datasource to see the last changes preserved.
You may use some design and architecture pattern for it.
Here is the link
https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52
Hope this will help.

Relationship among window, rootviewcontroller, childviewcontroller, navigationcontroller in iOS

I haven't really seen any resource that gives a good and simple explanations on relationship among window, rootviewcontroller, childviewcontroller, navigationcontroller and how they piece together in iOS development. Anyone one knows how to put this in a easy-to-understand way or any online resource or book that does a good job in explaining it?
Per the documentation on UIWindow:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIWindow_Class/
A UIWindow object provides the backdrop for your app’s user interface and provides important event-handling behaviors. Windows do not have any visual appearance of their own, but they are crucial to the presentation of your app’s views.
Xcode typically provides your application's main window, but you can add more if you need to.
From the documentation link you can see that UIWindow is actually a UIView
Enter your first view controller. Like providing a main window, when you start a new Project in Xcode the project template usually wires up your initial view controller, which as the name implies controls a view (UIView).
You could call this initial view controller your RootViewController but if you get a handle on the UIWindow you could just as easily swap out the current initial view controller's view for any other view controller view you like.
That probably doesn't help with hard and fast rules for things, but if I understand what you are asking, RootViewController is likely the initial view controller for you application. For example, if you are using Storyboards, Xcode typically makes Main.storyboard, you will see a gray arrow pointing to the UIViewController representation.
This is pointing to the Storyboards Initial View Controller. You can verify this from the Attributes Inspector. Select the view controller then select the attribute inspector:
So that's basically RootViewController. ChildViewController is just any other view controller that is a child of a view controller.
I assume what you are referring to is:
addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:
You can read more about these methods here:
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/
Under Implementing a Container View Controller
The quick gist of it is, A View Controller controls a view. View's can have subviews. Those subviews can come from other View Controllers. The methods outlined above pretty much just enable things like viewWillAppear, or viewWillDiappear to be called on the child view controller automatically when those methods are invoked on the parent view controller.
Per the docs:
By default, rotation and appearance callbacks are automatically forwarded to children. You may optionally override the shouldAutomaticallyForwardRotationMethods and shouldAutomaticallyForwardAppearanceMethods methods to take control of this behavior yourself.
a NavigationController is just like any other View Controller. It contains some special behavior for transitioning between views, but like other View Controllers it has a View (UIView) that it manages. A navigation controller could be your Initial View Controller / RootViewController just as any other View Controller can be, it all just depends on what you are trying to do. For example, a simple app that is just a list view, where you can tap an item and get a detail view could be constructed as:
1) Initial View Controller -> NavigationController
2) The NavigationController's first ViewController (Apple calls this a RootViewController) would then be a TableViewController.
3) Selecting a TableCell in the TableView (TableViewController manages a TableView) would then transition you to your Detail View Controller. The Navigation Controller knows how to do all that Sliding back and forth drama.
That's a pretty simplistic overview you can search the internet/youtube for more full featured tutorials outlining the same thing in more detail.
Example: https://www.raywenderlich.com/113388/storyboards-tutorial-in-ios-9-part-1
It's worth your time to do a few of these to get your bearings. Yes, it will likely cost you a few hours of your day. Take heart, everyone who ever started doing iOS development had to go though the same thing. =)

Hiding the current page of a UIPageViewController

I have a little question, related to a UIPageViewController. I use Swift as language, but if someone is unfamiliar with this new language, I understand Obj-C code too. My problem is relatively simple to describe, but not so simple to solve. I have a UIPageViewController set up. At some point, if the user pushes the current page of the page controller to the bottom, the page should disappear (the current view controller removed). I've tried a couple of things already. Before I continue, I'll explain some of the mechanics of my UIPageViewController that may help for an easier answer:
the page controller does not swipe trough an array of pre-configured view controllers. At the beginning, it takes in just one view controller. The rest of view controllers are calculated while the user swipes, trough the data source methods:
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
...
}
and
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
...
}
Each of the view controllers added, is an instance of a custom view controller that takes in a index, which indicates the data that this view controller should load. The limit of the pages in the page controller is defined by a count of the items available for the custom view controllers to load.
I've tried just one thing, and it almost worked. I'm describing it now that you know my page controller mechanics:
I swipe the current page down and it (graphically) disappears
I'm removing the data element linked to the current (and recently "deleted") view controller from the folder where all the others are stored
I'm updating the count of the elements inside the folder
The only problem with this solution is that after all this I still need the user to swipe to see the updates... Let me explain: after the current view controller disappears , I still have a white canvas in front of me... Only after the user swipes to get to a new page, the two data source methods are executed and the updates go live. After the swipe, the blank canvas is not there anymore (if I swipe back) and all other controllers are shown correctly. I just need to do one simple thing: after the view controller disappears, I should automatically (programatically) swipe back to the view controller before, so that the two data source methods are called and everything is updated...
So at the end, maybe my question should me more like: "How do I programatically swipe back to the previous UIPageViewController page?"
Any help will be appreciated!!
You can use the setViewControllers:direction:animated:completion: method of your UIPageViewController. You can do this right after step 3 above. It's your choice as to whether to use the viewController for the data element before the one removed, or the one after.
You can use setViewControllers:direction:animated:completion: as documented here.

Please clear some confusions regarding UIViewController

Please clear some confusions regarding UIViewController
I found this article Abusing UIViewController and here are the links link1 & link2
and summarised points
This is author's (and Apple’s) advice In a nutshell:
One (and only one) view controller should be responsible for a whole hierarchy (or screenful) of UIViews.
Mostly, you should only use one view controller per screen. Essentially the rootViewController of the current UIWindow should be the only UIViewController with a visible view.
Each different screen should have a different view controller i.e. one controller should not control more than one screen.
You should NOT nest custom UIViewControllers within a view hierarchy.
If more than one UIViewController hangs off the application’s UIWindow, only one of these will get the messages for changes in orientation. The other(s) will NOT get these messages.
Nested UIViewControllers are not guaranteed, or likely, to receive messages for changes in orientation or lifecycle messages such as viewDidAppear:, viewWillAppear:, viewDidDisappear: and viewWillDisappear: even though they inherit from UIViewController. Only the topmost UIViewController is certain to get these messages.
Please clear point number 2 and 3
because when we use UINavigationController or UITabBarController we use multiple subclasses of UIViewController. And ios device has only one screen.....
This article Abusing UIViewController highlight apple suggestion
Note: If you want to divide a view hierarchy into multiple subareas
and manage each one separately, use generic controller objects (custom
objects descending from NSObject) instead of view controller objects
to manage each subarea. Then use a single view controller object to
manage the generic controller objects.
and in apple docs under heading of Coordinating Efforts Between View Controllers apple saying
Few iOS apps show only a single screenful of content. Instead, they
show some content when first launched and then show and hide other
content in response to user actions. These transitions provide a
single unified user interface that display a lot of content, just not
all at once.....
My requirement is NOT to use any container or modal or popover, I want to do manual management, I have two view controllers VC1 & VC2. VC1 is the root view controller now I want to switch/transit/move to VC2 what should I do?
VC1 should be the only subclass of UIViewController and VC2 should be the subclass of NSObject to manage a particular view in VC1 hierarchy?(the show hide thing by apple doc).
VC2 can also be the subclass of UIViewController, I just remove VC1 from root view and add VC2 as root view?
or what is the correct way?
Container view controllers (like UINavigationController) allow working around the one-VC-per-screen rule. Since iOS 5, developers have been able and allowed to write our own container controllers (which aren't actually much different from normal VCs). Generally this means that writing non-VC controller objects is less necessary than it used to be.
In your situation, where you want to replace the root view controller, your option 2 makes more sense. Use VCs where you can, and non-VC controller objects only when you can't. Since you're replacing the whole screen's content, just switching the UIWindow rootViewController makes the most sense (edit: alternately, many devs would just use a navigation controller to present the second view, because it's simple and convenient).

What's the best controller to use for interactive books?

I'm creating an interactive touch book in iOS. I'd like to know what the best controller is to use for books. (e.g. UIViewController, NavigationController, etc.). I'd prefer to stay with storyboard options.
And secondly what is the best way to handle pages? A separate ViewController for each page? a separate view for each page?
UIPageViewController
From the docs:
Page view controllers allow users to navigate between view controllers
using the specified transition. Navigation can be controlled by the
user using gestures as well as programatically.
View controllers are either provided one at a time (or two at a time,
depending upon the spine position and double-sided state) via the
setViewControllers:direction:animated:completion: method, or provided
as-needed by the data source. Gesture-based navigation is enabled only
when a data source is provided.
To alter the behavior of this class, you should provide a data source
and delegate. This class is not intended to be subclassed.
As for your second question, yes it is easiest to manage each page as a view controller since UIPageViewController is a container view controller and it holds an array of view controllers.

Resources