i have a viewpagercontroller and have it running correctly with 3 pre set UIViewControllers, however when i load the app it first displays the first UIViewController, i would instead, like to display the second UIViewController first, however i am having trouble achieving this.
Here is my ViewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
if let firstViewController = orderedViewControllers.first {
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
}
}
Here is my orderedViewControllers
private(set) lazy var orderedViewControllers: [UIViewController] = {
return [self.newProfileViewController(vc: "UserContentViewController"),
self.newProfileViewController(vc: "ProfileViewController"),
self.newProfileViewController(vc: "NotificationViewController")]
}()
you can this function with your desired index,
func scrollToViewController(index newIndex: Int) {
if let firstViewController = viewControllers?.first,
let currentIndex = orderedViewControllers.indexOf(firstViewController) {
let direction: UIPageViewControllerNavigationDirection = newIndex >= currentIndex ? .Forward : .Reverse
let nextViewController = orderedViewControllers[newIndex]
scrollToViewController(nextViewController, direction: direction)
}
}
All you need to do is change the first bit of code that sets the viewcontrollers:
So change this:
if let firstViewController = orderedViewControllers.first {
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
}
To this:
if orderedViewControllers.count > 0 {
let secondViewController = orderedViewControllers[1]
setViewControllers([secondViewController],
direction: .forward,
animated: false,
completion: nil)
}
This will set the page view controller to the second view controller straight away and then your delegate methods on the page view controller should handle the swiping before and after to load the correct view controller.
Related
I am trying add UIPageView with static position counter. But UIPageView page hiding Counter Label
Following code - I am creating PageViewController in my ControllerView.
func createPageViewController(){
let pageVC = self.storyboard?.instantiateViewController(identifier:
Constant.storyIdPageViewIdentifier) as! UIPageViewController
pageVC.dataSource = self
if carsArray.count>0 {
let imageController = getImageViewController(withIndex: 0)!
let imageControllers = [imageController]
pageVC.setViewControllers(imageControllers, direction: .forward, animated: true, completion: nil)
}
pageViewController = pageVC
self.addChild(pageViewController!)
self.view.addSubview(pageViewController!.view)
pageViewController?.didMove(toParent: self)
}
Try using self.view.bringSubviewToFront(counterlabel)
I'm using PageViewController and tab bar. And I have a question which is 'how to move another view by touching button.' My app has 5 ViewControllers and they are on PageViewController. And the PageViewController is on ViewController. That ViewController is MainController. So I separated Main view, with about 4 : 1(PageViewController : tab bar). So tab bar is on MainController, MainController can changes ViewController when tab item is touched.
But what I want to make is a button on one of five ViewControllers which can change ViewController.
The button has not right to change ViewController. So I searched how to solve this problem but It couldn't find good solution.
I think the solution is very short, about 1 ~ 2 sentences.
I attached my code, so I hope anybody who know how to solve this problem please helps me.
I'm new in Swift, so explain detail please
This is a part of MainController
import UIKit
class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var pageViewController: UIPageViewController!
var subVC: [UIViewController] = []
var viewIndex: Int = 0
var tabIndicator1 = UIView()
var tabIndicator2 = UIView()
var tabIndicator3 = UIView()
var tabIndicator4 = UIView()
var tabIndicator5 = UIView()
var views = [UIView]()
override func viewDidLoad() {
super.viewDidLoad()
createVC() // make five ViewControllers
self.pageViewController = self.storyboard?.instantiateViewController(withIdentifier: "PageViewController") as! UIPageViewController
self.pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
self.pageViewController.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.addChildViewController(self.pageViewController)
self.view.addSubview(self.pageViewController.view)
let startVC = subVC[0]
viewIndex = 0
let viewControllers = NSArray(object: startVC)
self.pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: true, completion: nil)
self.pageViewController.didMove(toParentViewController: self)
createTabBar() // make Tab Bar
createIndicator() // make Tab Indicator
self.pageViewController.dataSource = self
self.pageViewController.delegate = self
}
...
func createVC() { // I have five ViewController files
let HomeVC = VCInstance(name: "Home")
let AccessVC = VCInstance(name: "AccessLog")
let RegisterVC = VCInstance(name: "Register")
let SettingVC = VCInstance(name: "Setting")
let HelpVC = VCInstance(name: "Help")
subVC = [HomeVC, AccessVC, RegisterVC, SettingVC, HelpVC]
}
func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: name)
}
....
You can use this code it might be help you.
extension UIViewController {
func goNextPage(animated: Bool = true) {
guard let currentViewController = self.viewControllers?.first else { return }
guard let nextViewController = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) else { return }
setViewControllers([nextViewController], direction: .forward, animated: animated, completion: nil)
}
func goPreviousPage(animated: Bool = true) {
guard let currentViewController = self.viewControllers?.first else { return }
guard let previousViewController = dataSource?.pageViewController(self, viewControllerBefore: currentViewController) else { return }
setViewControllers([previousViewController], direction: .reverse, animated: animated, completion: nil)
}
}
I have a UITabBarController as root view controller.
In this UITabBarController, I have 2 tabs: tabA and tabB.
tabA is a general view controller, and tabB is a viewController with a Container View in which a pageViewcontroller C is embeded.
Now there is a button in tabA, I want to realize the effect that when I click this button, it will jump to tabB and show the second page in C, everytime when click the button, it will call the function:
func swipeToIndex(ToIndex: Int, completion: (()->Void)? = nil) {
if self.currentPageIndex > 2 {
return
}
if ToIndex < self.currentPageIndex {
let toViewController = self.orderedViewControllers[ToIndex]
self.setViewControllers([toViewController], direction: .reverse, animated: true, completion: {finish in
self.currentPageIndex = ToIndex
completion?()
})
}
else if ToIndex > self.currentPageIndex {
let toViewController = self.orderedViewControllers[ToIndex]
self.setViewControllers([toViewController], direction: .forward, animated: true, completion: {finish in
self.currentPageIndex = ToIndex
completion?()
})
}
}
I can only realize it from the second time that I click the button. And the first time, it goes to the first page in C. I found it's something to do with the viewDidLoad(). when it calls the function swipeToIndex for the first time after
self.setViewControllers([toViewController], direction: .forward, animated: true, completion: {finish in
self.currentPageIndex = ToIndex
completion?()
})
it will call viewDidLoad, inside there sets the viewcontroller again like following:
if let firstViewController = orderedViewControllers.first {
setViewControllers([firstViewController],
direction: .forward,
animated: true,
completion: nil)
}
I have no clue how to avoid this when the first time call swipeToIndex
You will need to forward message a bit smarter and check if views have already been loaded.
In your page controller you should check if a view is loaded:
func swipeToIndex(ToIndex: Int, completion: (()->Void)? = nil) {
guard isViewLoaded else {
self.pageToSwipeTo = ToIndex
return
}
So you need to add
var pageToSwipeTo: Int? = nil
Then in viewDidLoad at the end try
if let pageToSwipeTo = pageToSwipeTo {
self.pageToSwipeTo = nil
self. swipeToIndex(pageToSwipeTo)
}
This is assuming the page view controller does already exist in your situation. This might actually not be true due to your hierarchy so you might need to forward the message even through the tab bar view controller... But try this procedure first.
I am using UIPageViewController having Next button that have same functionality like swipe to next view.
#IBAction func next(sender: UIButton!) {
let pageContentViewController = pageViewController.viewControllers![0] as! WelcomeViewController
let index = pageContentViewController.pageIndex + 1
if index < titleArray.count {
let vctoMove = self.viewControllerAtIndex(index) as WelcomeViewController
let viewControllers = NSArray(objects: vctoMove)
pageViewController.setViewControllers(viewControllers as? [UIViewController], direction: .Forward, animated: true, completion: nil)
}
}
I finnaly synchronized my segmentedController to the UIPageViewController in this way: when I swipe between pages, the segmented controller changes it's segment index. I want to know how to do the reverse too, when segmentedController's segment is tapped, to change the pageViewController page by segmentedController index. Here is my code:
class photoPageViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var segmentedControl: UISegmentedControl!
private var pageViewController: UIPageViewController?
var controllers = [thePageViewController]()
var thePage = thePageViewController()
override func viewDidLoad() {
super.viewDidLoad()
createPageViewController()
setupPageControl()
}
private func createPageViewController() {
var pageController = self.storyboard!.instantiateViewControllerWithIdentifier("PageController") as! UIPageViewController
pageController.dataSource = self
pageController.delegate = self
var firstController = getItemController(thePage.itemIndex)!
var startingViewControllers: NSArray = [firstController]
pageController.setViewControllers(startingViewControllers as [AnyObject], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
pageViewController = pageController
addChildViewController(pageViewController!)
self.view.addSubview(pageViewController!.view)
pageViewController!.didMoveToParentViewController(self)
}
private func setupPageControl() {
let appearance = UIPageControl.appearance()
appearance.pageIndicatorTintColor = UIColor.grayColor()
appearance.currentPageIndicatorTintColor = UIColor.whiteColor()
appearance.backgroundColor = UIColor.darkGrayColor()
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
let itemController = viewController as! thePageViewController
if itemController.itemIndex > 0 {
return getItemController(itemController.itemIndex-1)
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
let itemController = viewController as! thePageViewController
if itemController.itemIndex+1 < 3 {
return getItemController(itemController.itemIndex+1)
}
return nil
}
func getItemController(itemIndex: Int) -> UIViewController? {
var vc: thePageViewController? = nil
switch itemIndex {
case 0:
vc = self.storyboard!.instantiateViewControllerWithIdentifier("ViewController0") as! firstPhotoViewController
vc?.itemIndex = itemIndex
case 1:
vc = self.storyboard!.instantiateViewControllerWithIdentifier("ViewController1") as! secondPhotoViewController
vc?.itemIndex = itemIndex
case 2:
vc = self.storyboard!.instantiateViewControllerWithIdentifier("ViewController2") as! thirdPhotoViewController
vc?.itemIndex = itemIndex
default:
return nil
}
return vc
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return 3
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
func pageViewController(photoPageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers pageViewController: [AnyObject],
transitionCompleted completed: Bool)
{
if (!completed)
{
return;
}
segmentedControl.selectedSegmentIndex = thePageIndex
//thePageIndex is a global variable that changes when views from pageViewController appear
}
#IBAction func segmentedFunction(sender: AnyObject) {
switch segmentedControl.selectedSegmentIndex
{
case 0:
getItemController(0)
case 1:
getItemController(1)
case 2:
getItemController(2)
default:
println("...")
}
}}
I think you need to change your code a little bit! In my case I create several vc and put them to one array.
func createArrayOfControllers(){
newsLenta = self.storyboard?.instantiateViewControllerWithIdentifier("NewsLentaTableViewController") as NewsLentaTableViewController
mainPage = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageTableViewController") as MainPageTableViewController
onlinetranslation = self.storyboard?.instantiateViewControllerWithIdentifier("SingleTopicTableViewController") as SingleTopicTableViewController
tableViewControllers = [newsLenta, mainPage, onlinetranslation]
}
where tableViewController is global var var tableViewControllers = [UITableViewController]() ! I signed type TableViewController because all my vs's are type of table View controller. So the next function you need to change is
func viewControllerAtIndex(index : Int) -> UIViewController? {
if index > 2 || index < 0 {
return nil
}
return tableViewControllers[index]
}
In the end you just need to create action of segmentControl and reset your vc by index. Using this function:
func resetToMainPage(index: Int!) {
/* Getting the page View controller */
mainPageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("MainPageViewController") as UIPageViewController
self.mainPageViewController.dataSource = self
self.mainPageViewController.delegate = self
let pageContentViewController = self.viewControllerAtIndex(index)
segmentedControl.selectedSegmentIndex = index
self.mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
self.mainPageViewController.view.frame = CGRectMake(0, 95, self.view.frame.width, self.view.frame.height)
self.addChildViewController(mainPageViewController)
self.view.addSubview(mainPageViewController.view)
self.mainPageViewController.didMoveToParentViewController(self)
}
My question for your how do you update thePageIndex... I dont get that...
I found the way how to change UIPageViewController's content viewcontroller. I dont know is it right way or wrong but it works. Here is a code:
put this to viewdidload:
segmentControl.addTarget(self, action: "selectPageIndexBySegmentControl", forControlEvents: UIControlEvents.ValueChanged)
put it separte from viewdieload:
func selectPageIndexBySegmentControl(){
switch segmentControl.selectedIndex {
case 0:
println("zero index were selected")
pageContentViewController = self.viewControllerAtIndex(0)
mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
case 1:
println("first element were selected")
pageContentViewController = self.viewControllerAtIndex(1)
mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
case 2:
println("second element were selected")
pageContentViewController = self.viewControllerAtIndex(2)
mainPageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
default:
break
}
}