Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode XIB: how to implement a ScrollView or PageControl to swipe sub-views?

I'm building a typical Xcode 6 iOS app.

My goal is:

  • A screen that has an sub-area that can be swiped to change the content.

  • For example, the home screen has a logo image, a middle area that I want to be swipeable, and a bottom button.

  • When the user swipes (or taps) the middle area, the area shows the next (or previous) information, which is a typical UIImage and UILabel caption.

  • The rest of the screen stays the same, i.e. there is no navigation change.

The code is here. It use the recommendations from the StackOverflow post here.

My question: how can I implement the code below better, while still using an XIB?

My current implementation does work, and uses this approach...

A typical Swift Demo.swift file that is a UIViewController that has:

  • the page index, min, and max
  • outlets for the PageControl, UIImageView, and UILabel
  • actions for the page control change, and the image swipe or tap

A typical Demo.xib file that has:

  • a typical UIViewController for the entire screen
  • a UIImageView and UILabel for the changeable image and caption text
  • a PageControl to indicate what tutorial page the user is viewing

I am seeking better ways to accomplish this; I've read many of Xcode tutorials and so far none seem definitive for Xcode 6, XIBs, and Swift.

Here are some implementations that I've researched that seem promising...

Is there a way to implement a subview area in the XIB?

  • For example, can Xocde show the XIB with a rectangular area that is intended for the changeable content?

Is there an idiomatic way to write the code for changeable content?

  • For example, by using a ScrollView, perhaps that contains a UIPageViewController?

Is there a way to make a PageControl XIB object large enough to cover the entire UIImageView and UILabel, so I can skip making the UIImageView respond to gestures.

  • In my Xcode, the PageControl seems to have an uneditable height that is always 37.

The bounty will be for expert advice.

like image 770
joelparkerhenderson Avatar asked Apr 16 '15 01:04

joelparkerhenderson


People also ask

How to make View controller scrollable?

One way to do this is programmatically create an UIScrollView in your UIViewController . To control the scrollability you can set the ScrollView contentSize property.

How to implement ScrollView in Swift?

1. Add scrollView(1) in storyboard, add needed constraint to top/bottom/trailing/leading. 2. Then uncheck "Content Layout Guides" in Size inspector section for your scrollView.


2 Answers

To make a UIPageViewController swipe-able you should implement the UIPageViewControllerDataSource protocol and provide a view controller for the pageViewController(pageViewController:viewControllerBeforeViewController) -> UIViewController? and the ...viewControllerAfterViewController) methods.

Provide a custom view controller for each page that presents an image and label and takes them as properties so you can provide them from the PageViewController.

My trick it to create a method that instantiates a new view controller in these methods:

// MARK:- UIPageViewControllerDataSource

extension MyPageViewController: UIPageViewControllerDataSource {

  func viewControllerWithIndex(var index: Int) -> UIViewController! {
    let viewController = storyboard?.instantiateViewControllerWithIdentifier("MyViewController") as! MyViewController // This VC has to be in the storyboard, otherwise just use MyVC()

    // Adjust the index to be cyclical, not required
    if let count = data?.endIndex {
      if count == 1 && index != 0 { return nil }
      if index < 0 { index += count }
      index %= count
    }

    viewController.view.tag = index
    viewController.record = data?[index]

    return viewController
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    let index = viewController.view?.tag ?? 0
    return viewControllerWithIndex(index + 1)
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    let index = viewController.view?.tag ?? 0
    return viewControllerWithIndex(index - 1)
  }

  func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
    return countAndSetupPageControl()
  }

  func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
    return viewController?.view.tag ?? 0
  }
}

Now for the "sub-area" you will need to implement a ChildViewController. If you're using storyboards you can just drag a Container View and put PageViewController in the embedded view controller, otherwise you need to add the PageViewController.view as a subview and set the frame to the middle.

You can find more info in the apple documentation but basically you MUST call these methods:

addChildViewController(pageViewController)
view.addSubView(pageViewController.view)
pageViewController.view.frame = ... // This is your "sub-area"
pageViewController.didMoveToParentViewController(self)
like image 138
Yariv Nissim Avatar answered Oct 06 '22 15:10

Yariv Nissim


If you add a height constraint to PageControl you can set it's height to whatever you want.

I don't see a problem with your current implementation. Changing it to use a PageViewController would be quite more work.

If I were you I would add an animation in pageUpdate function so the image would fade in or slide in...

It would only make sense to use a PageViewController if you want to be able to scroll to the next page (as in content moving in the same time your finger is moving onscreen). And you can use a PageViewController or a CollectionView with paging enabled.

like image 22
pteofil Avatar answered Oct 06 '22 14:10

pteofil