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.
Related
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
More viewcontroller images are showing up in default blue background instead on original images. I want to change them to original images and also want to increase UITableViewCell's height.
I have tried implementing tableview delegate methods on UITabbarController, but nothing working out.
Even moreNavigationController is also not changing.
1) Where do i have to write these custom methods viewDidLoad or viewWillAppear. Also shouldSelectViewController is not getting called. First time when i select a tabbar item it is being called and when i select the more item it is not getting called.
2) Where should i implement UITableView delegate methods.
My screen -
required screen -
A solution using swift is helpful. Thanks in advance.
I got the requirement working. The step wise procedure I followed is
Take a ViewController which extends UITabbarController.
Take an array with five elements exactly.(If more than five then default More functionality gets enabled).
First four tabs as required and fifth should be 'More' tab. With required tab images.
For 'More' tab create a View Controller which extends UITableView delegates and datasources. And implement respective methods of delegate and datasources.
Take an array of the Cells you want to display and display them.
Link this 'More' View Controller to the 'More' tab.
Change the images in tableview in cellForRowAtIndexPath method.
Run the application and check by selecting 'More' tab. This time it should show the changed UI.
When each cell should show different View Controllers on selecting the cells, then segue to different view controllers using the segues from ViewController (Not segue from the tablecell). Define a unique segue id for each segue and show the viewcontrollers based on switch or ifelse conditions in shouldSelectViewController using performSegueWithIdentifier.
Thanks #KKRocks for the valuable links.
There's some content to be unpacked here. I am not entirely certain I fully understand the question but I'll go ahead and reply partially as best I can.
ViewDidLoad and ViewWillAppear
You add code in viewDidLoad for initialization. This method will run when your view is originally loaded and unless you're instantiating the controller every time it will only run once ( in this case you dont because you're using the prebuilt tabbar system which takes care of that for you)
So I would add the styling code in viewDidLoad()
When a viewController is to be displayed, viewWillAppear() will be called. This will happen every time so if you need to perform repetitive tasks like network calls, restyling based on some other data, refreshing your tables, you should do it here.
Table methods
For doing whatever you need to do with a table you will most likely need both UITableViewDelegate and UITableViewDataSource to your view controller. Look up any UITableView tutorial online they're many very comprehensive and will explain how to add all the table methods you need in your viewController.
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]
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 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...