Segue on Swipe on last page of UIPageView - ios

I have a PageViewController with 3 pages. I want to segue away from PageViewController to AnotherViewController when user swipes from right to left on the last page. I cant figure out how to do it.
The only trigger for swipe is
func viewControllerAtIndex(index : Int) -> UIViewController?
and looking for index == 3 and then perform the segue BUT index == 3 never reaches because there is no 4th page? What am I missing?

There is no index 3. The last index is 2. Because it starts from 0 - 1 -2.

Related

Swift/Xcode: Why does the tab bar disapear if I navigate away from the page?

So I have a list of exercises. Each exercise is a button that segues to a screen that shows a video of the exercise. I then have a back button on the video page that segues back to the initial list of exercise page. However, when I segue back, the tab bar at the bottom is no longer there. Any idea why it's disapearing? Thanks so much!
Sorry about last answer it was for some other question on stackoverflow just misplaced it. Please take a look in your on video page controller if you have this selected. Also check if you have these lines in your code
self.hidesBottomBarWhenPushed = YES;
Change your segue to perform segue to TAB BAR CONTROLLER
Create a UITabBarController file. Inside it , create a struct and a simple if condition
class TabBarController: UITabBarController {
struct defaultIndexSelection {
static var selectedIndex = "0"
}
override func viewDidLoad() {
super.viewDidLoad()
if defaultIndexSelection.selectedIndex == "0"
{
self.tabBarController?.selectedIndex = 0
}
else if defaultIndexSelection.selectedIndex == "1"
{
self.tabBarController?.selectedIndex = 1
}
else if defaultIndexSelection.selectedIndex == "2"
{
self.tabBarController?.selectedIndex = 2
}
else if defaultIndexSelection.selectedIndex == "3"
{
self.tabBarController?.selectedIndex = 3
}
}
Set this TabBarController as the class of your TabBarController.
Now on your back buttons action , add this line.
TabBarController.defaultIndexSelection.selectedIndex = 0
// if you want to have the tab at index 0 selected and
shown on back button press or 1 if you want first tab selected
Thats it, whenever you press back from whatever viewController, it will segue back to tabbarcontroller and then select the index depending on which viewcontroller you came from.
TabBarController.defaultIndexSelection.selectedIndex = 0 being your 1st tab
TabBarController.defaultIndexSelection.selectedIndex = 1 being your 2nd tab
TabBarController.defaultIndexSelection.selectedIndex = 2 being your 3rd tab
TabBarController.defaultIndexSelection.selectedIndex = 3 being your 4th tab

UIPageViewController initial swipe called twice

The below function is how I display different views when a user swipes right where
self.viewControllerAtIndex() is my own custom function that returns a view. The problem is that the first swipe outputs "---------swipe Right before 0" twice. And then works perfectly like expected afterwards.
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
print("---------swipe Right before " + String(index))
index += 1
print("---------swipe Right " + String(index))
if index == (products!.count) {
index = 0
}
return self.viewControllerAtIndex(index:index)
}
=====CONSOLE OUTPUT=====
---------swipe Right before 0
---------swipe Right 1
---------swipe Right before 0
---------swipe Right 1
func viewControllerAtIndex(index: Int) -> ViewController{
return ViewController.init(id: index)
}
For some reason, every other swipe after the first works as expected. The initial swipe is what causes the console output above. This causes my view sequence to look like below (2 views)
First Swipe
View1
Second Swipe
View1
Third Swipe
View2
Fourth Swipe
View1
Fifth Swipe
View2
I'm also initiating my uiPageViewController like so
let array = [ViewController](repeating: ViewController.init(videos: (self.videos![self.products![self.index].id]!)), count: 1)
self.UIViewPageController?.setViewControllers(array, direction: UIPageViewControllerNavigationDirection.forward, animated: false, completion: nil)
So I'm creating a new ViewController on viewDidLoad and then when a user swipes, I'm creating new ViewControllers
I think you should avoid doing index state management in this method. Apple does not guarantee the circumstances under which this method is called. If I had to paraphrase, I would say that while the framework is asking you for the view controller that should come after the provided one, you are answering a different question: Which view controller comes after the one you previously told us about?
To get around this, you need to use your original array of view controllers, find the index of the passed-in view controller in that array, and return the view controller that comes next (or nil if you are at the end of the array).
Too long for a comment ...
Chris Trahey's is the correct answer.
I had the same problem, based on the misunderstanding that the viewControllerBefore/viewControllerAfter methods meant "What should happen if the user swipes right/left". Like you said, these methods only answer the question: "Which view controller comes before/after a given view controller?" They should only answer that question, without any side effects.
A solution for some scenarios would be to add an index property to the view controller class, and set that index on creation. That's useful if you're not working directly with an array of view controllers, but create them on the fly. Then, instead of saying array.index(of: vc), you can say vc.index.
See here: https://stackoverflow.com/questions/25795093/swift-uipageviewcontroller-always-repeats-second-viewcontroller#=
EDIT:
Oh, and if you want to actually react to a page turn, you can do that in pageViewController(_:didFinishAnimating:previousViewControllers:transitionCompleted:).

ButtonBarPagerTabStripViewController updateIndicator toIndex is wrong

I need to add or remove items from the navigation bar when the user changes screen so I have a code like:
override func updateIndicator(for viewController: PagerTabStripViewController, fromIndex: Int, toIndex: Int, withProgressPercentage progressPercentage: CGFloat, indexWasChanged: Bool) {
super.updateIndicator(for: viewController, fromIndex: fromIndex, toIndex: toIndex, withProgressPercentage: progressPercentage, indexWasChanged: indexWasChanged)
if indexWasChanged {
if toIndex == 2 {
rightBtn.alpha = 1
} else {
rightBtn.alpha = 0
}
}
}
rightBtn is simply a button on the right end of my navigation bar.
However during my testing runs I noticed that if the user taps on the ButtonBar instead of swiping to change screen, the fromIndex and toIndex is wrong. It will still be the values of the last change.
E.g. when the user swipes from the third screen to the second, the fromIndex will be 2 and toIndex 1 but if the user taps on the third button on the bar, the fromIndex will still be 2 even though it is expected to be at 1 the toIndex will also stay at 1 even though now it should be 2.
This results in my rightBtn not showing if the user swipes from the third screen then taps the bar back to the third.
Is there a way to obtain the correct toIndex during such a scenario or can it be fixed?
The first part is the buggy part where I navigate by tapping directly on the barbutton, the second part without the pointer is navigation by swiping with works fine, the Icon is only suppose to appear on the Third Tab
I have gotten a solution, for anyone with the same problem, there is a currentIndex in ButtonBarPagerTabStripViewController. So this:
if indexWasChanged {
if currentIndex == 2 {
rightBtn.alpha = 1
} else {
rightBtn.alpha = 0
}
}
will work over the original codes in the question.
Also I went to the GitHub project and found that someone else who is facing this problem already reported it. Hopefully it will be fixed and both methods will work.

Strange behaviour during mid-swipe back

I'm experiencing a strange glitch where I can use the previous view controller before the top view controller has been dismissed.
At my main view controller I have a table view with the delegate function didSelectRowAtIndexPath. The function is below:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("commentsSegue", sender: self)
}
This works great, however if I am already showing this screen, I can select it again if I half-swipe back. This is sort of hard to explain but you can use a finger to swipe back and the other to select a cell on the main viewcontroller. This creates another segue to a new "commentsSegue". I can do this as many times as I like and it will action many segues.
I have tried to overcome this by using
if (self.presentingViewController?.presentedViewController == self) {
and also
if (self.navigationController?.topViewController.title == self.title) {
But both of these functions return the main viewcontroller as the active view controller instead of the "commentsSegue" controller.
How can I stop this behaviour from occurring?
On swipe create a Notification which check if your destination controller .isKindOfClass your current one. If not , make the segue.

In Swift How to change the selected tab bar

I am new to swift programming and I have a Tabbed application with 2 UITabBar items , I want that when user taping the second tab, application set the selected tab index to 0 and move user to the first tab. I tried this code in my SecondViewController.swift's viewDidLoad :
self.tabBarController?.selectedIndex = 0
but it doesn't work.
This works:
override func viewDidAppear() {
self.tabBarController?.selectedIndex = 0
}
See this answer for a good explanation of viewDidLoad() vs. viewDidAppear.
Relevant excerpt:
This is where you want to perform any layout actions or do any drawing in the UI - for example, presenting a modal view controller

Resources