I am building my first "real" iOS app and want to make sure that I'm going down the sane path.
Distilled to its essence, the app will provide three distinct ways of visualizing a set of data. Not counting any possible modal confirmation views, I am currently envisioning that I will need 6 UIViews (or subclasses thereof). The first three each provide a unique way of visualizing the data. The fourth will be a table view to select which data set is to be viewed. The final two will form a parent/child heirarchy and will be used to display/edit user preferences for customizing the visualizations---one to display the list of data sets and the other to display details of a single selected data set.
My initial plan for the HMI is for the user to be able to sweep left/right between the views OR to select the view from a segmented control in the right position in the navigation bar. The user can access the preference view via a gear icon in the left position of the navigation bar (which will change to "back" when the preferences are being displayed). The title position will contain a button showing the name of the current data set and will trigger bringing up the list of data sets. Selecting one of the data sets make the current data sets. Swiping a data set or a long press on it will bring up its details view.
There will also be a number (4 or 5) of items in a toolbar for recording/editing/saving/sharing the data within the dataset. This will not be visible when viewing/editing preferences or the data set list.
My question is whether or not it makes sense to wrap all of this in a UINavigationController or if I want to use a custom controller, UINavigationBar, and UIToolbar. It seems that using the navigation controller will simplify the code necessary to use the navigation and tool bars. But, I am wondering if the mixture of hierarchal views and non-heirarchal (peer?) views (the data visualization views) will cause me undue headaches.
Thoughts?
Thanks!
mike
p.s. I'm thinking that the benefits of using the UINavigationContrtoller will win out, but I wanted to see if anyone knows of a reason that this is a bad approach.
Edit: I added the following figure per suggestion that it might help clarify my vision of the HMI.
If you want to swipe left & right between view controllers, or tap on a page control, it sounds like you should be looking at a UIPageViewController
https://developer.apple.com/reference/uikit/uipageviewcontroller
You implement 2 delegate methods, one to supply the page after a given view controller, the other to return the page beforeā¦
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
}
To have a "circular" set of pages, just return the view controller for page[0] after the view controller for the last page, and return the last page when before page[0]
Related
Sorry for the long and possibly confusing question. In this I have 2 main problems with my code, those being: 1- When I embed my viewControllers in a UINavigationController and add a bar button item, nothing appears, yet it appears when I add it to the pageViewController. Secondly, I am wondering if there is a way to do this differently and use one button on the pageView (which appears on all viewcontrollers in it) and just determine what the user was looking at when they pressed the button and are taken to another viewcontroller.
I am trying to build a page-based application, and I have set up the application with 7 view controllers (One for each day of the week). I then have an AddViewController, where users can add data to a certain day. I was wondering if there is a way to only use 1 addView linked to the NavBar on the PageViewController, as when I embed all other viewControllers and add a bar button, it does not show up.
With the pageViewController being embedded, this is what it looks like with a bar button on it.
This then leads to:
Which works well, however I am wanting to pass data to various arrays (one for each viewController), and I want to know which ViewController the user wishes to add to (based off what day they were on). Is there a way to determine this and then unwind to the viewController and append the right data to the right array or should I have one addView per dayViewController? If that is the case, I am coming across the issue whereby the bar button items do not appear on the viewControllers when they are embedded in a navigationController. It looks like this:
StoryBoard: (Example: MondayViewController)
The outcome is a missing barButton: (Keep in mind I changed the tint Colour to white so it would be visible)
I was wondering if anyone has the answer to either of my problems, and once again, thanks for taking the time to look at this array of questions in one problem.
Any suggestions are welcome !
Rowan,
You can do this:
Create an UINavigationViewController and then embed an UIPageViewController in it.
In the data source for the UIPageViewController implement these two methods:
- pageViewController:viewControllerBeforeViewController:
- pageViewController:viewControllerAfterViewController:
Here you will return the correct instance of your DayViewController for each position (or nil if you are on the first/last page). Your data model would also be set here.
Add your "Add" bar button to the navigation bar of the UIPageViewController and let it push your AddViewController. When pushing the AddViewController provide to it the info on which day is currently visible. You will probably need to keep track of this your self. Use the - pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted: method of the UIPageViewController delegate.
I want to display a UIViewController this way, that is: an upper viewcontroller slides out with a left-to-right animation and the lower one displays. Then, when you click the left button, this viewcontroller covers the other one again.
This is a very common UX pattern and I see lots of people doing it with third party components (eg. SWRevealViewController).
The question is: if I don't want to do it with a third party library, how can I do it?
IMO: Apple has stated that it's more of a design anti-pattern and appeal to popularity shouldn't be considered a good argument for this kind of design.
What you're looking for is a UIViewController containment and transitioning. Create a UIViewController class that accepts a, say, menuViewController (the lower one in your case) and an array of view controllers that can be displayed by tapping menu items.
Grab all the titles from the collection of view controllers and display them in menu view controller. Next by tapping the items in menu just use
- transitionFromViewController:toViewController:duration:options:animations:completion:
method for animating the transition between chosen view controllers.
It not so trivial to make, that's why people suggest to use some 3rd-party library.
But basically you want to create container view controller, add there your menu and main view controller above it and handle gesture recognition.
Basically what I want to do is depicted in the image below:
However this only loads the middle and third interface, the first is hidden both from swiping onto and in the circle indicators at the bottom.
I'd like to be able to load the second interface and swipe left for the first and swipe right for the third. Is there a way to achieve this?
Building my first Apple Watch app over here :)
Looks like there is a concept of UINavigationController-ish behaviour built into the WKInterfacesController.
Take a look at: pushControllerWithName(_:context:)
And from some docs I found here:
Hierarchical. This style is suited for apps with more complex data models or apps whose data is more hierarchical. A hierarchical interface always starts with a single root interface controller. In that interface controller, you provide controls that, when tapped, push new interface controllers onto the screen.
EDIT:
Looking into this some more. WatchKit is currently very limited by the looks.
The best solutions I could come up with was to add the three InterfaceController, with segues is between. Left -> Main -> Right.
Then assign a custom SKInterfaceController for Main:
class InterfaceController: WKInterfaceController {
override init() {
super.init()
becomeCurrentPage()
}
}
This creates an annoying animation in the beginning where you will see "Left" on start and how "Main" is animated pushed in. I don't see any better way to do this at this early stage of WatchKit.
The placement of the ViewControllers have no real "physical" meaning.
A segue (the arrows) simply defines a way to navigate from "this" ViewController to another one.
http://www.raywenderlich.com/81880/storyboards-tutorial-swift-part-2
It is possible to create as many segues from one ViewController to other ViewControllers as needed. You can name these segues, and trigger the one you want from storyboard send events or code for specific events (like swipe gestures).
To get the animation of actually sliding the view to the left would require a custom transition:
http://mathewsanders.com/animated-transitions-in-swift/
I am writing an app in xCode 6.2 using storyboards and there is a need to present 2 different lists within a page view type setup (similar to Beat - Music Player).
The PageView controller is something I have never used before, so, I have looked at several examples and all deal with an Image View and changing the content of that based on an array. Whereas, what I am essentially trying to achieve is two separate ViewControllers being swiped between using the PageView controller. Is this even possible? If so, would anybody be able to point me in the right direction please?
the magic does by the two delegate methods viewControllerBeforeViewController and viewControllerAfterViewController ...
when you load the first viewcontroller to your pageviewcontroller with setViewControllers:#[theFirstViewController] the pageviewcontroller will ask the two delegates for the next and the previous vcs... you are responsible that the delegates returns the vcs you want to display, no matter what kind of vc you want to display...
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.