I have a UIPageViewController in my program. I have added a UITextView programmatically at the top of UIPageViewController.I want to update the text of UITextView with each swipe to page 1 of n or 2 of n or ….
How should I update the TextView to have the correct image number? Where should I call updateStatusLabelText function?
The reason why I used UITextView is that I could not add a UILabel with constraints through code to the top of UIPageViewController.
First class is as follows:
class MainPageViewController: UIPageViewController {
let dS = MainPageViewControllerDataSource()
var statusText : String = ""
var statusTextView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
statusTextView = UITextView(frame: view.bounds)
statusTextView.text = statusText
statusTextView.editable = false
statusTextView.textAlignment = .Center
statusTextView.font = UIFont(name: statusTextView.font!.fontName, size: 18)
statusTextView.textColor = UIColor.blackColor()
view.backgroundColor = UIColor.whiteColor()
view.addSubview(statusTextView)
view.sendSubviewToBack(statusTextView)
}
func updateStatusLabelText(arrayKey:Int){
statusTextView.text = "\(arrayKey + 1) of \(imageArray.count) "
}
override func viewWillAppear(animated: Bool) {
dataSource = dS
setViewControllers([dS.viewControllerAtIndex(0) as TutorialViewController], direction: .Forward, animated: true, completion: nil)
}
}
Second class
class MainPageViewControllerDataSource: NSObject, UIPageViewControllerDataSource,UIPageViewControllerDelegate {
var tutorialViewControllerDelegate: TutorialViewControllerDelegate?
var pageIndex = Int()
func viewControllerAtIndex(index: Int) -> TutorialViewController {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("tutorialVC") as! TutorialViewController
vc.myImage = imageArray[index]
vc.pageIndex = index
self.pageIndex = index
return vc
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
var index = (viewController as! TutorialViewController).pageIndex
index -= 1
switch index {
case Int.min ... (-1):
return nil
case NSNotFound:
fatalError("NSNotFound. Should crash.")
case imageArray.count..<Int.max:
return nil
default:
return viewControllerAtIndex(index)
}
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var index = (viewController as! TutorialViewController).pageIndex
index += 1
switch index {
case Int.min ... (-1):
return nil
case NSNotFound:
fatalError("NSNotFound. Should crash.")
case imageArray.count ..< Int.max:
return nil
default:
return viewControllerAtIndex(index)
}
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return imageArray.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return pageIndex - 1
}
}
Third class:
class TutorialViewController: UIViewController, UIPageViewControllerDelegate {
#IBOutlet weak var imageToPresent: UIImageView!
var itemIndex: Int = 0
var myImage : MyImage?
var pageIndex = Int()
override func viewDidLoad() {
super.viewDidLoad()
imageToPresent = myImage
}
}
Related
I have an UIViewController with a UITableView. Then I create a PageViewController with two viewcontroller. Pageview doesn't work if I pass data to child. If I change
setViewControllers([subjective], direction: .Forward, animated: true, completion: nil)
to
setViewControllers([firstVC], direction: .Forward, animated: true, completion: nil)
Pageview work but data don't pass. I don't have any idea about it. Help me please. Thanks
Code Work:
pageview controller class:
import UIKit
class PageVC : UIPageViewController, UIPageViewControllerDelegate, UIPageViewControllerDataSource {
var lblhoten = String()
var lblngaysinh = String()
var lblsodt = String()
lazy var VCArr: [UIViewController] = {
return [self.VCInstance("ThongTinBNPage2"),
self.VCInstance("ThongTinBNPage3")]
}()
private func VCInstance(name: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier(name)
}
override func viewDidLoad() {
super.viewDidLoad()
self.dataSource = self
self.delegate = self
if let firstVC = VCArr.first {
let subjective = self.storyboard?.instantiateViewControllerWithIdentifier("ThongTinBNPage2") as! VCSubjective
subjective.lblhoten = lblhoten
subjective.lblngaysinh = lblngaysinh
subjective.lblsodt = lblsodt
setViewControllers([subjective], direction: .Forward, animated: true, completion: nil)
}
}
public func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
guard let viewcontrollerindex = VCArr.indexOf(viewController) else {
return nil
}
let previousindex = viewcontrollerindex - 1
guard previousindex >= 0 else {
return VCArr.last
}
guard VCArr.count > previousindex else {
return nil
}
return VCArr[previousindex]
}
public func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
guard let viewcontrollerindex = VCArr.indexOf(viewController) else {
return nil
}
let nextindex = viewcontrollerindex + 1
guard nextindex < VCArr.count else {
return VCArr.first
}
guard VCArr.count > nextindex else {
return nil
}
return VCArr[nextindex]
}
public func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return VCArr.count
}
// The selected item reflected in the page indicator.
public func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
guard let firstviewcontroller = viewControllers?.first,
let firstviewcontrollerindex = VCArr.indexOf(firstviewcontroller) else {
return 0
}
return firstviewcontrollerindex
}
}
VCSubjective:
import UIKit
class VCSubjective: UIViewController {
#IBOutlet var hoten: UILabel!
#IBOutlet var ngaysinh: UILabel!
#IBOutlet var sodt: UILabel!
var lblhoten = String()
var lblngaysinh = String()
var lblsodt = String()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
hoten.text = lblhoten
ngaysinh.text = lblngaysinh
sodt.text = lblsodt
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The problem here is that you are referencing two completely different objects.
In viewDidLoad you create ThongTinBNPage2 viewController and then add it to the viewControllers property of the pageViewController. However, the objects stored in VCArr are two totally different viewControllers.
Let's think about it this way:
When viewDidLoad is called you create viewController object #1
Then you assign the viewController object #1 to the viewControllers object of the pageViewController making the value of viewControllers = [object #1]
In pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? and pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? you reference the VCArr object. On the first call to VCArr, it lazily creates two completely different view controller objects [object #2, object #3]
To fix this code you need to do the following:
if let firstVC = VCArr.first {
let subjective = firstVC // DO NOT create different VC here
subjective.lblhoten = lblhoten
subjective.lblngaysinh = lblngaysinh
subjective.lblsodt = lblsodt
setViewControllers([subjective], direction: .Forward, animated: true, completion: nil)
}
I am using a UIPageViewController to load multiple UIViewControllers but every time I try scrolling past the last ViewController or even try scrolling the opposite direction on the start of the pageController I get a blank screen as shown below. The blank view is never really fully loaded onto the view but ideally I would like the blank screen to simply have a white colour background hence not obviously visible to the user.
Any help will be greatly appreciated.
import UIKit
class MainPageVC: UIPageViewController
{
var totalPages: [UIViewController] = [UIViewController]()
#IBOutlet weak var rightBarButtonItem: UIBarButtonItem!
override func viewDidLoad()
{
super.viewDidLoad()
let attributes: [String : AnyObject] = [NSFontAttributeName: Constants.defaultFont]
rightBarButtonItem.setTitleTextAttributes(attributes, forState: .Normal)
self.delegate = self
self.dataSource = self
let eyeWearVC = storyboard!.instantiateViewControllerWithIdentifier("eyeWear") as! EyeWearVC
let fitnessVC = storyboard!.instantiateViewControllerWithIdentifier("fitness") as! FitnessVC
let healthVC = storyboard!.instantiateViewControllerWithIdentifier("health") as! HealthVC
let environmentVC = storyboard!.instantiateViewControllerWithIdentifier("environment") as! EnvironmentVC
totalPages.append(eyeWearVC)
totalPages.append(fitnessVC)
totalPages.append(healthVC)
totalPages.append(environmentVC)
setViewControllers([eyeWearVC], direction: .Forward, animated: true, completion: nil)
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
func viewControllerAtIndex(index: Int)-> UIViewController
{
if self.totalPages.count == 0 || index >= self.totalPages.count
{
return UIViewController()
}
return totalPages[index]
}
extension MainPageVC: UIPageViewControllerDelegate
{
}
extension MainPageVC: UIPageViewControllerDataSource
{
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
return totalPages.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
return 0
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{
var currentIndex: Int = totalPages.indexOf(viewController)!
if currentIndex == 0 || currentIndex == NSNotFound
{
return nil
}
currentIndex -= 1
return self.viewControllerAtIndex(currentIndex)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController?
{
var currentIndex: Int = totalPages.indexOf(viewController)!
if currentIndex == NSNotFound
{
return nil
}
currentIndex += 1
if currentIndex == totalPages.count
{
return nil
}
return self.viewControllerAtIndex(currentIndex)
}
}
Add
view.backgroundColor = .whiteColor()
in viewDidLoad()
With the following code, the page control has jumped twice instead of once during a single page swap. I need to add the UIPageViewController as subview as below, how can I make the pagecontrol act right? Thank you!
import UIKit
class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate{
var pageViewController: UIPageViewController!
let pagesArray = ["Page1ViewController", "Page2ViewController","Page3ViewController"]
let pageControl : UIPageControl = UIPageControl(frame: CGRectMake(100, 600, 200, 20))
func viewControllerAtIndex(index: Int) -> UIViewController? {
let vc = storyboard?.instantiateViewControllerWithIdentifier (pagesArray[index])
return vc
}
func pageViewController(pageViewController:UIPageViewController,
viewControllerBeforeViewController
viewController: UIViewController) -> UIViewController?{
if var index = pagesArray.indexOf(viewController.restorationIdentifier!){
if index > 0 {
index--
self.pageControl.currentPage = index
return viewControllerAtIndex(index)
}
}
return nil
}
func pageViewController(pageViewController:UIPageViewController,
viewControllerAfterViewController
viewController: UIViewController) -> UIViewController?{
if var index = pagesArray.indexOf(viewController.restorationIdentifier!){
if index < pagesArray.count - 1 {
index++
return viewControllerAtIndex(index)
}
}
return nil
}
override func viewDidLoad() {
super.viewDidLoad()
pageControl.numberOfPages = 3
pageControl.currentPage = 0
pageControl.tintColor = UIColor.redColor()
pageControl.pageIndicatorTintColor = UIColor.blackColor()
pageControl.currentPageIndicatorTintColor = UIColor.orangeColor()
if let vc = storyboard?.instantiateViewControllerWithIdentifier("MyPageViewController")
{
self.addChildViewController(vc)
self.view.addSubview(vc.view)
self.view.addSubview(pageControl)
pageViewController = vc as! UIPageViewController
pageViewController.dataSource = self
pageViewController.delegate = self
pageViewController.setViewControllers([viewControllerAtIndex(0)!], direction: .Forward, animated: true, completion: nil)
pageViewController.didMoveToParentViewController(self)
}
}
}
try this
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController?
{
let identifier = viewController.restorationIdentifier
self.index = self.identifiers.indexOfObject(identifier!)
if index == identifiers.count - 1 {
return nil
}
//increment the index to get the viewController before the current one
self.index = self.index + 1
return self.viewControllerAtIndex(self.index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
{
let identifier = viewController.restorationIdentifier
self.index = self.identifiers.indexOfObject(identifier!)
if index == 0 {
return nil
}
//decrement the index to get the viewController before the current one
self.index = self.index - 1
return self.viewControllerAtIndex(self.index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
{
return self.identifiers.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int
{
return 0
}
//For Navigation Bar Tint and BG Color
var NavBarBGColor = CommonUtilities.RGBColor("#2574A9")
var NavBarTintColor = UIColor.whiteColor()
var pageViewController: UIPageViewController!
var pageTitles: NSArray!
var pageImages: NSArray!
#IBOutlet weak var Open: UIBarButtonItem!
override func viewDidLoad() {
//Navigation Bar Tint and BG Color
self.navigationController?.navigationBar.tintColor = NavBarTintColor
self.navigationController?.navigationBar.barTintColor = NavBarBGColor
super.viewDidLoad()
//Menu Button Click
Open.target = self.revealViewController()
Open.action = Selector("revealToggle:")
//Pan Gesture Recognizer for page navigation
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
//Page View Controller for Men
self.pageTitles = NSArray(objects: "Try","And")
self.pageImages = NSArray(objects: "page1","page2")
self.pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController
self.pageViewController.dataSource = self.pageViewController.dataSource
/*var startVC = self.viewControllerIndex(0) as ContentMenuViewController
var viewControllers = NSArray(object: startVC)
self.pageViewController.ViewControllers(viewControllers, direction: .Forward, animated: true, completion: nil)*/
self.pageViewController.view.frame = CGRectMake(0, 30, self.view.frame.width, self.view.frame.size.height - 60)
self.addChildViewController(self.pageViewController)
self.view.addSubview(self.pageViewController.view)
self.pageViewController.didMoveToParentViewController(self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func MenuRestartBtn(sender: AnyObject) {
}
func viewControllerAtIndex(index: Int) -> ContentMenuViewController
{
if ((self.pageTitles.count == 0)) || (index >= self.pageTitles.count)
{
return ContentMenuViewController()
}
var vc: ContentMenuViewController = self.storyboard?.instantiateViewControllerWithIdentifier("") as! ContentMenuViewController
vc.imageFile = self.pageImages[index] as! String
vc.titleText = self.pageTitles[index] as! String
vc.pageIndex = index
return vc
}
//Page View Controller Data Source
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var vc = viewController as! ContentMenuViewController
var index = vc.pageIndex as Int
if (index == 0 || index == NSNotFound)
{
return nil
}
index--
return self.viewControllerAtIndex(index)
}
func pageViewController(pageController: UIPageViewController, ViewControllerAfterViewController viewController: UIViewController) -> UIViewController{
var vc = viewController as! ContentMenuViewController
var index = vc.pageIndex as Int
if (index == NSNotFound){
return nil;
}
index ++
if (index == self.pageTitles.count){
return nil
}
return self.viewControllerAtIndex(index)
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return self.pageTitles.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}
You cannot return nil when function should return UIViewController wich your trying to do in:
func pageViewController(pageController: UIPageViewController, ViewControllerAfterViewController viewController: UIViewController) -> UIViewController
Replace above with:
func pageViewController(pageController: UIPageViewController, ViewControllerAfterViewController viewController: UIViewController) -> UIViewController?
I'm new to protocols and pageview controllers and I tried to something I hoped was simple. To pass a variable value from the content viewcontroller to the page list viewcontroller but it doesn't work so I'm doing something wrong...
In my storyboard I have a ViewController (as the Page List viewcontroller) and embedded in a navigation controller. The navigation bar has a button on it.
There is a PageContentViewController that has a label.
The code I use follows (EDITED with the accepted solution provided by #Tom Elliott):
protocol setRoomOnScreenProtocol {
func updateRoomOnScreen(myRoom: String)
}
class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, setRoomOnScreenProtocol {
#IBAction func press1(sender: AnyObject) {
println("roomOnScreen: \(roomOnScreen)")
println("pageTitles: \(pageTitles)")
}
#IBOutlet weak var btn1: UIBarButtonItem!
let pageTitles = ["Room 1", "Room 2", "Room 3", "Room 4"]
var count = 0
var pageViewController : UIPageViewController!
var roomOnScreen: String = ""
override func viewDidLoad() {
super.viewDidLoad()
reset()
}
func updateRoomOnScreen(myRoom: String) {
roomOnScreen = myRoom
println("roomOnScreen (PGL): \(roomOnScreen)")
}
func reset() {
/* Getting the page View controller */
pageViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageViewController") as! UIPageViewController
self.pageViewController.dataSource = self
let pageContentViewController = self.viewControllerAtIndex(0)
self.pageViewController.setViewControllers([pageContentViewController!], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: nil)
self.pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
self.addChildViewController(pageViewController)
self.view.addSubview(pageViewController.view)
self.pageViewController.didMoveToParentViewController(self)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
var index = (viewController as! PageContentViewController).pageIndex!
index++
return self.viewControllerAtIndex(index)
}
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
var index = (viewController as! PageContentViewController).pageIndex!
if (index <= 0) {
return nil
}
index--
return self.viewControllerAtIndex(index)
}
func viewControllerAtIndex(index : Int) -> UIViewController? {
if ((self.pageTitles.count == 0) || (index >= self.pageTitles.count)) {
return nil
}
let pageContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as! PageContentViewController
pageContentViewController.delegate = self
pageContentViewController.titleText = self.pageTitles[index]
pageContentViewController.pageIndex = index
return pageContentViewController
}
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
return pageTitles.count
}
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
return 0
}
}
and the PageContentViewController:
class PageContentViewController: UIViewController {
var pageIndex: Int?
var titleText : String!
var delegate: setRoomOnScreenProtocol!
#IBOutlet weak var label1: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.label1.text = self.titleText
}
override func viewDidAppear(animated: Bool) {
if let actualDelegate = self.delegate {
actualDelegate.updateRoomOnScreen(titleText)
} else {
println("error")
}
doMore()
}
func doMore() {
println("showing...:\(titleText)")
}
}
When I move through the pages I correctly get the output:
roomOnScreen (PGL): Room 1
showing...:Room 1
roomOnScreen (PGL): Room 2
showing...:Room 2
But when I hit the navigation bar button I get no value...
roomOnScreen:
pageTitles: [Room 1, Room 2, Room 3, Room 4]
What am I doing wrong...?
Thanks!
The line:
self.delegate = ViewController()
Is actually creating a brand new instance of ViewController each time it is called, so the original ViewController that is visible is not receiving the message.
I'd suggest setting the delegate when you initially create the pages:
let pageContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PageContentViewController") as! PageContentViewController
pageContentViewController.delegate = self