Last Updated: February 25, 2016
· jaryl

Using UIScrollView and UIPageControl in RubyMotion

As a new user of UIKit and RubyMotion, I chose the simplest thing to implement on a project that I have to work on (hooray for learning on the job), which looks like this (sorry I couldn't get it to animate in CoderWall):


I put both the UIScollView and UIPageControl elements in a view controller, and off we go:

class SlideshowController < UIViewController

  def viewDidLoad

    numberOfPages = 3

    @scrollView = UIScrollView.alloc.init
    @scrollView.frame = CGRectMake(0, 0, App.window.frame.size.width, App.window.frame.size.height)

    @scrollView.pagingEnabled = true
    @scrollView.backgroundColor = UIColor.blackColor

    @scrollView.contentSize = CGSizeMake(@scrollView.frame.size.width * numberOfPages, @scrollView.frame.size.height)

    @scrollView.showsHorizontalScrollIndicator = false
    @scrollView.showsVerticalScrollIndicator = false

    numberOfPages.times do |i|
      view = UIView.alloc.initWithFrame(CGRectMake(@scrollView.frame.size.width * i, 0, @scrollView.frame.size.width, @scrollView.frame.size.height))
      view.backgroundColor = UIColor.alloc.initWithPatternImage(UIImage.imageNamed("slideshow-#{i + 1}"))

    @scrollView.delegate = self
    self.view.addSubview @scrollView

    @pageControl = UIPageControl.alloc.init
    @pageControl.frame = CGRectMake(0, 0, App.window.frame.size.width, 80)
    @pageControl.numberOfPages = numberOfPages
    @pageControl.currentPage = 0

    self.view.addSubview @pageControl

  def scrollViewDidScroll(scrollView)
    @pageControl.currentPage = @scrollView.contentOffset.x / @scrollView.frame.size.width


Essentially, you have to create a scroll view with a content size that maps your entire slideshow. You then create views that you position in your scroll view, and then you let the library do its magic.

To link it up with the page control, you just handle the scrollViewDidScroll delegate method to set the currentPage attribute.

I was also trying to allow users to tap on the page control element to jump to specific pages, but struggled with some issue with it, I added another delegate method here:

def clickPageControl(sender)
  frame = @scrollView.frame
  frame.origin.x = frame.size.width * @pageControl.currentPage

  @scrollView.scrollRectToVisible(frame, animated: true)

And I hooked it up with the page control like so in viewDidLoad:

@pageControl.addTarget(self, action: "clickPageControl:", forControlEvents: UIControlEventAllEvents)

The problem with this was that when clickPageControl was called, it would start scrolling the scroll view, which would in turn trigger scrollViewDidScroll, and the page control would do some back-and-forth thing which didn't look so great.

Any ideas on fixing that?

UPDATE: I fixed that by using the scrollViewDidEndDecelerating delegate, which only gets called when it finishes decelerating as it name implies, instead of scrollViewDidScroll.