[Swift 5] How to make a horizontal paging UIScrollView with Auto Layout in Storyboards

Update May 2020: Fully updated for Xcode 11 and Swift 5.1.

Since Auto Layout came to life, the task of making adaptive user interfaces that support all screen sizes, has become a piece of cake. Although that’s a bit of a challenge in some of the situations, this technology has helped get things done easier and faster than before with more enhanced and optimised UI.

In this tutorial, you will learn how to make a cool starting slideshow for your app, something you would show to the user the first time he uses the app, so that you guide him over the main features of your app. These kind of slideshows are famous and are implemented in many apps with different fancy layouts and animations.

Without further ado, let’s slide in 🙂

Open up Xcode, select “File\New\Project” from the menu, choose the “Single View App” template and make sure the default language is Swift and Storyboard as User Interface.

The slideshow you will implement in this tutorial consists of four slides with fixed logo but moving background images, you will also put some text in there and change it dynamically while you scroll. Also, in the last slide, a button will get shown with a nice fade-in animation to allow the user to exit the slideshow and explore the app effectively.

Select ‘Main.storyboard‘ from the ‘Project navigator‘ view, then choose one of the device sizes from the “View as” panel. Let’s choose the iPhone 11 model to work with together.

Choose a device model to layout with from the "View as" panel in Xcode 11

Note: After you choose the device model, Xcode inferred a UIKit Size of 414*896 points for the screen, if you want to setup your UI elements in a different dimension view, you can change the size from the ‘Size inspector‘ view, like below.

Change the view size from the Size inspector in Xcode 11

Let’s keep the 414*896 points size so we can follow each other along the way 🙂

Time to import the slides images and icons you will use in the project, download the zip file here.

From the ‘Project navigator‘ view, select Assets.xcassets, then click the ‘+’ icon at the bottom and select ‘New Image Set‘ from the list.

Add a New Image Set in Xcode 11 Assets.xcassets

Name it ‘Slide 1’, you may notice the new asset is provided with 3 resolutions placeholders (1x, 2x and 3x), here you will take care of the Retina and Retina HD (2x and 3x respectively). So drag the two images named slide1@2x.png and slide1@3x.png from the folder you dowloaded to the 2x and 3x placeholders in Xcode.

add images to the xcassets folder

Repeat the same steps to make new set of images for the rest of the downloaded assets, and drag their images to the relevant placeholders, call the images set ‘Slide 2’, ‘Slide 3’, ‘Slide 4’, ‘Icon’ and ‘Text Icon’.

Assets.xcassets in Xcode 11 after you added all assets

Cool, now you will setup a UIScrollView and enable paging on it. From the ‘Object library‘, drag a UIScrollView object to the view and make sure it’s filling the whole view area, you can ensure that by setting the X to 0, Y to 0, Width to 414 and Height to 896 from the ‘Size inspector‘. Switch to the ‘Attributes inspector‘ view, ensure the ‘Paging Enabled‘ property is checked, the ‘Bounce On Scroll‘ and ‘Show Horizontal Indicator‘ properties are unchecked.

[Xcode 11]Add UIScrollView to the view in Storyboard

Let’s add some basic constraints so that the scroll view will fill the whole screen on different screen sizes. Select the Scroll View object from the Document Outline view, then activate the leading, trailing, top and bottom constraints for the selected view.

Note: Make sure the checkbox ‘Constrain to margins‘ shown in the Pin menu is UNchecked.

[Xcode 11] Activate leading, trailing, top and bottom constraints
Double check Xcode 9 is applying constraints to the superview

Important: Make sure that the constraints are applied between the scrollview and its superview. Sometimes this will not be the case and the “Safe Area” (Top and Bottom Layouts in Xcode < 9) is instead applied. Like below:

If this is the case, double click each constraint to access its details and make sure to replace “Safe Area” by “Superview“. This way we make sure the scroll view is lay out completely against the whole view bounds.

[Xcode 9] double click each constraint to access its details and make sure to replace "Safe Area" by the "Superview". This way we make sure the scroll view is lay out completely against the whole view bounds.
Click to view in better resolution

Auto Layout may throw two errors regarding its content size:

UIScrollView Has ambiguous scrollable content height; UIScrollView has ambiguous scrollable content width

The errors above indicate that Auto Layout doesn’t know about the scroll view height and width contents. To fix this, you can uncheck the Content Layout Guides from the Size inspector.

UIScrollView Content Layout Guides

Drag a UIImageView from the Object library to the view, make sure it’s a subview of the root view and not the UIScrollView because it will not be dependant on the scrollable content and need to be fixed while the other content will scroll horizontally 🙂

[Xcode 9]Make sure the image view is not a subview of the scrollview because it will be fixed and not dependant on the scrollable content

Ensure the image view is selected, switch to the ‘Attributes inspector’ view and set the ‘Image’ property to ‘Icon’ and ‘Content Mode’ to ‘Aspect Fit’, then switch to the ‘Size inspector’ view and set X=153, Y=52, Width=109 and Height=100.

To finish with the icon, select the ‘Align‘ menu and check the ‘Horizontally in Container‘ constraint then click the ‘Add constraint‘ button at the bottom of the menu to apply the constraint. Also select the ‘Pin‘ menu and activate the top spacing, width, height and the aspect ratio constraints, then click the ‘Add Constraint’ button to apply the changes.

[Xcode 9] Top spacing, width, height and Aspect ratio constraints
Click to view in better resolution

Note: As shown in the animation above, you may need to make sure the Top spacing is set against the top of the view and not the ‘Safe Area’. To do so, select the small arrow at the right of the Top spacing value and select ‘View’, like shown below:

[Xcode 9]Make sure the top spacing is against the top of the view and not the Safe Area

Go on and add another UIImageView to hold the text icon below the main icon. From the ‘Object library’, drag a ‘UIImageView’ object to the view and make sure it’s a subview of the root view and not the UIScrollView. Set its image to ‘Text Icon’ and its mode to ‘Aspect Fit’ from the ‘Attributes inspector’ view. Next, change its position and frame to X=67, Y=180, Width=240 and Height=66 from the ‘Size inspector’ view.

Finally, Set the following constraints to the text icon:

1/ Activate the ‘Horizontally in Container’ constraint from the ‘Align’ menu.
2/ Activate the ‘Top’ spacing, ‘Width’ and ‘Height’ constraints from the ‘Pin’ menu.
3/ Maintain a Control click and drag a line from the text icon to the scroll view and select the ‘Aspect Ratio’ constraint from the list.

Here is a quick animation demonstrating the steps above:

How to add Auto Layout constraints  in Xcode 9 new Assistant Editor
Click to view in better resolution

So far so good, let’s add a text view to hold some text for the slideshow, the text view will change its text as the scroll view is moving. Drag a UITextView object to the view and ensure it’s a subview of the root view as you did for the two previous image views. Next, retrace the following steps for a quick setup of the text view:

1/ From the ‘Size inspector’ view, set the X to 68, Y to 284, Width to 239 and Height to 128.
2/ From the ‘Attributes inspector’ view, set the ‘Alignment’ to the center and the ‘Background‘ color to ‘Clear Color’. Also, UNcheck the ‘User Interaction Enabled’ property.
3/ Activate the ‘Horizontally in Container’ constraint from the ‘Align’ menu.
4/ From the ‘Pin’ menu, activate the ‘Top’, ‘Leading’, ‘Trailing’ and ‘Aspect Ratio’ constraints, and make sure that the “Constrain to margins” checkbox is UNchecked.

You are almost done. Quickly add a UIPageControl from the ‘Object library’ to the view (again, it should be a subview of the main view and not the scroll view).

Let’s customise the page control color, reposition it and set some constraints. Retrace the following steps:

1/ Select ‘Size inspector‘, set X to 174, Y to 620 and Width to 67.
2/ Select ‘Attributes inspector‘ and set the number of pages to 4 and Hex Tint Color to #de354b.
3/ Select the ‘Align’ menu and activate the ‘Horizontally in Container’ constraint.
4/ Select the ‘Pin’ menu and activate the Top spacing and Width constraints.

Good job, now let’s finish up and put a button in the bottom that will remain hidden till the last slide is reached. Drag a UIButton object from the ‘Object library‘ to the view, as usual, it should be a subview of the main view and not the scroll view since you need this button to remain fixed while scrolling.

Follow the steps below to set up the button:

1/ From the ‘Size inspector‘, set X to 87, Y to 807, Width to 239 and Height to 55.
2/ From the ‘Attributes inspector‘, change the text to say ‘Let’s Start’, set the color of the text to white and the background color of the button to the Hex code #de354b. Also, set the Alpha value to 0 to hide it (this is important for the fade in animation you will implement later).
3/ From the ‘Pin’ menu, activate the leading, trailing and bottom constraints.
4/ Control drag from the bottom dotted part of the button to the top part of the same button, select ‘Aspect Ratio’ from the list.

The following animation illustrates step 4:

[Xcode 9] Height aspect ratio for the button

The view hierarchy of the final screen will look like this:

Final view Hierarchy

Note: The only required order in the view hierarchy is that the scrollview should be placed on top of all other views, like shown above.

You are done with the UI setup, everything is on place, now we need to hook them up to the code to make them alive 🙂

To do so, switch to the ‘Assistant editor’ view so that the editor is split to show both the storyboard and the ViewController.swift file:

Assistant editor in Xcode 11

Hold the control button and drag a line from the scroll view in the storyboard to the swift file (right below the class name). Name the outlet ‘scrollView‘ and click ‘Connect’ button.

Repeat the previous step on the text view, the page control and the button. Name them ‘textView’, ‘pageControl’ and ‘startButton’ respectively.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var startButton: UIButton!
    @IBOutlet weak var pageControl: UIPageControl!
    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var scrollView: UIScrollView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

What you did is very important because you will need to interact with all connected outlets from the code.

Now time to write some code to finish up. Switch back to the ‘Standard editor‘ with the ViewController.swift file opened. First you need to make the class adopt the UIScrollViewDelegate protocol, change the class definition to the following:

class ViewController: UIViewController, UIScrollViewDelegate {

Cool, now locate the viewDidLoad function and place the following code inside (right after the super.viewDidLoad call):

//1
self.scrollView.frame = CGRect(x:0, y:0, width:self.view.frame.width, height:self.view.frame.height)
let scrollViewWidth:CGFloat = self.scrollView.frame.width
let scrollViewHeight:CGFloat = self.scrollView.frame.height
//2
textView.textAlignment = .center
textView.text = "Sweettutos.com is your blog of choice for Mobile tutorials"
textView.textColor = UIColor.black
self.startButton.layer.cornerRadius = 4.0
//3
let imgOne = UIImageView(frame: CGRect(x:0, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgOne.image = UIImage(named: "Slide 1")
let imgTwo = UIImageView(frame: CGRect(x:scrollViewWidth, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgTwo.image = UIImage(named: "Slide 2")
let imgThree = UIImageView(frame: CGRect(x:scrollViewWidth*2, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgThree.image = UIImage(named: "Slide 3")
let imgFour = UIImageView(frame: CGRect(x:scrollViewWidth*3, y:0,width:scrollViewWidth, height:scrollViewHeight))
imgFour.image = UIImage(named: "Slide 4")
        
self.scrollView.addSubview(imgOne)
self.scrollView.addSubview(imgTwo)
self.scrollView.addSubview(imgThree)
self.scrollView.addSubview(imgFour)
//4
self.scrollView.contentSize = CGSize(width:self.scrollView.frame.width * 4, height:self.scrollView.frame.height)
self.scrollView.delegate = self
self.pageControl.currentPage = 0

Let’s explain some parts of your code:

//1 You set the frame of the scroll view to be equal to the frame of the container view, this is very important since you cannot ensure this to be equal to all screen sizes right from Interface builder, so you need to programmatically retrieve the root view frame and assign it to the scroll view to guarantee it will fill all the screen.

//2 That should be self explanatory, you just loaded a text for the first slide and set the text color of the text view. Also, you changed the corner radius of the button to look nice 🙂

//3 Here you added some background images for the four slides, set their frames accordingly to appear the one next to the other and embed them to the scroll view. Now with the paging enabled, the slides will be bouncing smoothly.

//4 Finally, and most importantly, you changed the content size of the scroll view to reveal the new size of the slides being added horizontally.

Now you will finish up your work by implementing a delegate function related to the scroll view behavior, you need to be notified each time the scroll view has finished scrolling and which is the current page being shown at that moment. This is important in order to: change the current page indicator dot, change the text in the text view and also show the button if it’s the last slide being shown.

Place the following code somewhere in your ViewController.swift file before the closing bracket (I put comments to explain the steps):

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView){
// Test the offset and calculate the current page after scrolling ends
let pageWidth:CGFloat = scrollView.frame.width
let currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1
// Change the indicator
self.pageControl.currentPage = Int(currentPage);
// Change the text accordingly
if Int(currentPage) == 0{
      textView.text = "Sweettutos.com is your blog of choice for Mobile tutorials"
}else if Int(currentPage) == 1{
      textView.text = "I write mobile tutorials mainly targeting iOS"
}else if Int(currentPage) == 2{
      textView.text = "And sometimes I write games tutorials about Unity"
}else{
      textView.text = "Keep visiting sweettutos.com for new coming tutorials, and don't forget to subscribe to be notified by email :)"
// Show the "Let's Start" button in the last slide (with a fade in animation) 
     UIView.animate(withDuration: 1.0, animations: { () -> Void in
      self.startButton.alpha = 1.0
     })
 }
}

Cool, you just put the last piece of the puzzle, your code above will be running each time after you swipe the scroll view, and will check for the current page to change the dots accordingly, and also, you just performed a sweet fade in animation for the button on the last slide to show it.

Run the project and enjoy the slideshow 🙂

How to Auto Slide it ?

Eunice Obugyei, one of our sweet readers, asks me how to make this scrolling app slides automatically without the need to manually scroll it left and right. So here I will explain you how to do so easily 🙂

First, you need to schedule a timer in order to fire a function call every n seconds. The called function will do the sliding movement automatically for you.

Locate the viewDidLoad method and place the following NSTimer set before the closing bracket of the method:

Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(moveToNextPage), userInfo: nil, repeats: true)

As you can see, this timer will call the moveToNextPage function every 2 seconds. The repeats argument is very important and should be set to true in order for the moveToNextPage function to run continuously every 2 seconds. Otherwise the call to the function will occur only one time.

Next, you need to implement the moveToNextPage function, where the auto sliding will be implemented. Place the following code before the closing bracket of the class:

@objc func moveToNextPage (){
        
let pageWidth:CGFloat = self.scrollView.frame.width
let maxWidth:CGFloat = pageWidth * 4
let contentOffset:CGFloat = self.scrollView.contentOffset.x
        
var slideToX = contentOffset + pageWidth
        
if  contentOffset + pageWidth == maxWidth
{
      slideToX = 0
}
self.scrollView.scrollRectToVisible(CGRect(x:slideToX, y:0, width:pageWidth, height:self.scrollView.frame.height), animated: true)
}

The code above will calculate the contentOffset of the scrollview and set its new X position accordingly. If the contentOffset reached the last page, then the X position will be reset to 0.

Last thing before you run the new auto sliding scroll view, you need a way to tell the scroll view delegate about any scrolling changes so that it will update the page indicator and the text accordingly. One way to do so is to rename the delegate method scrollViewDidEndDecelerating you already implemented to scrollViewDidEndScrollingAnimation. The reason why is that scrollViewDidEndDecelerating is not called when we scroll programmatically using scrollRectToVisible, unlike the scrollViewDidEndScrollingAnimation protocol method.

Run your app and enjoy your auto scrolling slideshow!

That’s it folks 🙂

As usual, you can download the completed project for this tutorial. Download the default scrolling slideshow project here, and download the auto scrolling slideshow project here.

How will you implement your app starting slideshow? what fancy animations will you use? Feel free to write your thoughts below.

Malek
iOS developer with over than 11 years of extensive experience working on several projects with different sized startups and corporates.

82 Comments

  1. Great tutorial as always. Just a quick question. I added a View Controller to the project and connected it with the “Let’s Start” button. Now my question is how to a set it so that the page view shows only once after the users runs/instals the program for this first time. Then afterwards it defaults to a specific view. I have seen other app do it that way.

  2. Hi 🙂

    This can be done easily using NSUserDefaults. You basically need to test over a flag (boolean variable) and react accordingly. The best place to do so is inside the “didFinishLaunchingWithOptions” delegate method in the app delegate class of your app. So head over to that method and implement the following logic inside:

    1) Test the flag value (let’s say its name is “isFirstTimeUse”): if userDefaults.boolForKey(“isFirstTimeUse”)

    2) If it’s “true”, then show the slideshow, AND SET IT TO “false”

    3) If it’s false, then skip the slideshow and show another view controller.

    Note: NSUserDefaults store persistent data to your device, so don’t worry about that. The only way values are erased is to remove the app from the device.

    Hope this help 🙂

  3. Hello. Im super new to coding so i have a quick question. When you say, “make sure it’s a subview of the root view and not the UIScrollView”, how to do that because I can’t get the image and text to show when I run. I can only get 2 photos to slide, and the rest is blank. What am I doing wrong? Thanks in advance

  4. Hi, you should ensure the UIImageView is placed right under the scroll view in the document outline view, and not inside the scroll view. As shown in the following screenshot. This way, it’s a subview of the root view and it won’t be dependant on the scroll view.

  5. Hi! Nice tutorial! It works nice! I have a quick question. I have images (543px by 551px) and I want to scroll these images in just a upper part of the view (not entirely full view), so I changed the scrollView.frame.height, aspect ratio constraint and position (storyboard).

    I also changed contentSize but I scroll just 2 of 3 images (I use AspectFit). Even if I did not change contentSize, last image is cropped (I think, it didn’t load full).

    I copy the code. Thank for your help.

    //1 CHANGES HERE
    // self.scrollView.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
    // let scrollViewWidth:CGFloat = self.scrollView.frame.width
    // let scrollViewHeight:CGFloat = self.scrollView.frame.height

    self.scrollView.frame = CGRectMake(0, 0, self.view.frame.width, self.scrollView.frame.height)
    let scrollViewWidth:CGFloat = self.scrollView.frame.width
    let scrollViewHeight:CGFloat = self.scrollView.frame.height

    //2
    textView.textAlignment = .Center
    textView.text = “Sweettutos.com is your blog of choice for Mobile tutorials”
    textView.textColor = .whiteColor()
    self.startButton.layer.cornerRadius = 4.0

    //3 CHANGES HERE
    var imgOne = UIImageView(frame: CGRectMake(0, 0,scrollViewWidth, scrollViewHeight))
    imgOne.image = UIImage(named: “Slide 1”)
    var imgTwo = UIImageView(frame: CGRectMake(scrollViewWidth, 0,scrollViewWidth, scrollViewHeight))
    imgTwo.image = UIImage(named: “Slide 2”)
    var imgThree = UIImageView(frame: CGRectMake(scrollViewWidth*2, 0,scrollViewWidth, scrollViewHeight))
    imgThree.image = UIImage(named: “Slide 3”)

    self.scrollView.addSubview(imgOne)
    self.scrollView.addSubview(imgTwo)
    self.scrollView.addSubview(imgThree)

    // self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width * 3, self.scrollView.frame.height)
    self.scrollView.contentSize = CGSizeMake(UIImage(named: “Slide 1”)!.size.width * 3, self.scrollView.frame.height)

    self.scrollView.delegate = self
    self.pageControl.currentPage = 0

  6. Hi Roberto 🙂

    You don’t have to change the scroll view frames nor its content size. Just change the width and height of the image container to the size you are comfortable with. For example:
    var imgOne = UIImageView(frame: CGRectMake(0, 0,543, 551))

  7. Hi Malek, very good tutorial. I have a problem with the UIPageControl. I can’t change the color and the background. I checked with your settings. XCode and SDK all latest. Do you have any idea?

  8. Hi 🙂

    Select the UIPageControl, then select the Attributes inspector. The background color is called “Background”, the current page dot color property is called “Current Page”, and the rest of the dots color property is called “Tint Color”. Check the screenshot I took below:

  9. Absolutely great tutorial! I’ve come back to this a couple times for different aspects of a project I’m working on, and I keep finding something new and useful.

    Best wishes in your career Malek!

  10. Extremely helpful, thank you for the great tutorial, Malek!
    I need to ask a question by hoping you could lead me to the right way. I will already use the paging scrollview that you presented. However, as a separate view, I need a scrollview that I can put some images to click to open the corresponding views, consider images are the section buttons, plus they need to be scrolled vertically (not horizontally and I only need it to be portrait application to make it simple) and work in different devices as in your sample. I attached an image to show how it looks like. Can I still use scrollview for this purpose? Should I put a view in the scrollview that holds the images?

  11. Hi Malek 🙂

    Thank you for your prompt response. I already started building the project by following the way I asked you and using the valuable information from your post. I am not working with Xcode 7 yet, I think I’ll get it worked with what I have so far with Xcode 6.4 for this one. I was able to put things in right places I guess. In fact, I even attempted to create my own UIView subclass with xib to create image views – they have many properties like label, alpha, font for label etc.. so reusable custom control sounded really attractive and it is amazingly good so far. I can’t promise to not asking more questions 🙂 but I’ll let you know about the progress. Thank you, once again!

  12. I know this is too soon but I stuck at some point. I create my scroll view, perfectly applied layout rules and it works great (actually it should work great, all it needs to fit in the screen). Then I create the content view inside the scroll view, applied auto layout , looks ok. Then I programmatically place the image views inside the content view, and set scroll view content size by using the content view bounds or frame. It never lets me scroll, like content view never gets higher than scroll height even I know it contains more than enough sub views (image views). It only works if I set content view height manually, naturally.
    And I am desperately stuck 🙁

  13. Hi Suat,

    After adding the images programmatically, you need to change the contenSize frame of the scroll view with a new CGSize values via the setContentSize method. Can you debug the content size and the scroll view frames ? also, try to add the subviews to the scroll view and all the stuff from within the viewDidAppear method. Let me know how it goes.

  14. Hi Malek,
    If I change the contentSize in viewDidAppear then it changed the scrollView size, however, I still cannot get the updated view height even in viewDidAppear, so I can’t find out what would be the contentSize height of the scrollView. I think the reason is that I am not adding constraints for the imageViews when I put them into the view programmatically – I think I should actually do that so it will resize the view automatically – I was thinking that containerView will be resized automatically when I put subviews in it. Yes, I know I am too new at this :). I am using the part you explained above successfully by the way. Thank you very much for your help!

  15. Wow! I did something and I figured that I know nothing about auto layout! What I did was setting contentView EqualWidth with the superview and then also setting contentView AspectRatio itself – then everything works like a charm in every device! Here is the amazing part – I didn’t even need to set scrollView contentSize, it just works magically!

  16. Malek, I promise this will be last post for today 🙂
    Still following your scrollView sample above and it is really great, helping me a lot. However, I want to make it work like: images are stacked one over another, like layers, and when I swipe on the top image, I want the top one move left during I swipe it, second one in the stack reveals from black alpha 1 to alpha 0 while I was still swiping and from the already swiped area on the scene, and finally top one goes out and next one shows up. They wouldn’t be adjacent at the edges but one below another, so moving speed will be also not the same, just to give the next one a movement feel. Do you have tip or sample like this? I kind of think that it is not scrollView but animation but have no idea how to start correctly.

    Once again, thanks a lot!

  17. Hi Suat 🙂
    Do you have more code I can see? so that I can help you better on this. Or maybe better, a github repository I can fork to help you go to the right way with your project.
    Malek

  18. Hi Malek,

    I am all new to swift so it takes some time to understand new concepts however I think I got something working 🙂

    Please watch it if you have time: https://youtu.be/sazhIi7acMY

    Once I got it working with all settings I am planning, I will put it into Github. It might be something really simple to do or even an existing component but it was a big challenge for me and I feel good to get it this far 🙂

    I guess I should also learn using github too, right? 🙂

    Malek, thank you for your help! (I think I remember your name from some tutorials at http://raywenderlich.com where I was visiting often when I was working on objective-c a few years ago). I will make sure following your tutorials.

  19. You are welcome, Suat! I am glad to help 🙂
    Let me know when you push your sample project to a repo on github.
    Yes, it’s me, the same guy who was writing for ray’s blog 🙂

  20. Hey Malek_T, thanks for the great and illustrated tutorial. I have a question: I could not understand the difference of use between the pure UIScrollView vs UIPageViewController. For example, in my project I dont know which one I should go: I have some featured articles above my tableview, and the user should be able to swipe between the images, which image with some information, like the ss from the WildCard app attached. Anyway, many applications contain the same layout and I’m sure you get the idea. Which one do you think I should go? Thanks again! Regards!

  21. One more thing. I was having a problem after the tutorial: My scrollview also was having vertical scrolling. I solved the issue with:

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width * 4, 1.0)

    Got this solution here: http://stackoverflow.com/questions/7535210/how-to-disable-just-vertical-scrolling-in-a-uiscrollview

    I dont really know why I got this problem – I applied the tutorial on a view that already possess a UITableView and some 3rd librarys. Anyway, if someone else have the same problem this works.

  22. Find out what was causing the problem: “self.view.frame.height” was not getting the right value for some reason, maybe because my scrollview are outside the content UIView frame.

  23. Great tuto! Please make in the future, a tutorial teaching how to merge 2 xcode projects in one. Will be very usefull! thanks a lot

  24. Hey! Great tutorial, really helpful 🙂 I was wondering if it would be possible to gain some help though, I was looking to use this feature to display different buttons rather than images, this would be so the user can scroll through and select a character which loads a different view controller (hopefully that makes sense). I’m still new to coding and it would be great if you could assist me in anyway on doing this? Thank you!

  25. Hi Konsey,

    Sure, you can simply replace UIImageView with UIButton, and that should work correctly. Also, you can keep your character objects as UIImageView and attach a UITapGestureRecognizer object to detect click events so that behave like UIButtons.

    Let me know how it goes, if you already tried something and got troubles, then feel free to ask on the Forum section, I will be there to assist you further 🙂

  26. Hi Malek,

    Nice example. Paging scroll views aren’t used often enough in iOS apps – maybe because they have historically been difficult to implement.

    I took a stab at implementing your example using MarkupKit, an open-source project I developed. Just thought I’d share the results in case you were interested:

    http://gkbrown.org/2016/01/09/creating-a-paging-scroll-view-using-markup/

    If you have a minute to check it out, I’d be interested to hear what you think. Thanks!

  27. Hi Greg, just download your project code, it’s just amazing. Great work you put on the library. Keep it up 🙂

  28. HI Greg, can I use MarkupKit to build any component. For example, if I want AirBnB style table view with image and related text on top of the image, can I do that as well? Also, what are the constraints of using your library in the future? will you charge for it?

  29. Awesome tutorial! @Malek_T:disqus

    I modified your code a bit but having an issue.

    Instead of having a set background image, my app dynamically chooses an image based on a Switch case that is run after an API call. My thought is to somehow get the result of my case (String) and place it in the:

    imgOne.image = UIImage(named: “dynamicBackground”)

    Is there a better way to do this? My API is called in viewDidLoad() so the relevant data should be available on load. It was working fine before I added the ScrollView. I just want it to show the same dynamic background on all pages.

    (I made sure the background ImageView isn’t nested inside the ScrollView FYI)

    Thanks for any help with this!

    James

  30. Hello! great tutorial thank you! I saved much time with large part of my application. I have a question, how protect scrollview to stop between images? I tried to put in the end of scrollViewDidEndDecelerating
    something like this:

    let slideToX = currentPage * pageWidth

    self.scrollView.scrollRectToVisible(CGRectMake(slideToX, 0, pageWidth, CGRectGetHeight(self.scrollView.frame)), animated: true)

    but in that case scrolling to proper page will started only after scroll animation is over.

  31. Hi 🙂
    What do you try to do? By “protect scrollview to stop between images”, do you mean setting a delay between pages transition ?

  32. This is a great tutorial, thanks a lot! I’ve been wondering for a long time how to do a paging scroll view in Swift. I didn’t think it was so easy. It took me about 2 hours and I finally understand how this is done.

  33. Thanks for this tutorial! What about having an additional option to slide manually between the automatic slides? My ScrollView slides automatically every 8 seconds, but if I slide manually before time limit is reached, the page control doesn’t get noticed about the slide. Will work on this extension.

  34. Yello Sascha 🙂

    If you want to further detect manual besides the automatic scrolling, you need to implement the scrollViewDidScroll protocol method. For this case, implement the following:

    func scrollViewDidScroll(scrollView: UIScrollView)
    {
    scrollViewDidEndScrollingAnimation(scrollView)
    }

    Here, the scrollViewDidScroll will call the scrollViewDidEndScrollingAnimation protocol method which you already implemented to update the page control dots. Hope this helps!

  35. I believe the content size is somehow incorrectly set or calculated. If you have ‘n’ slides to show (for example 4), how much is the value of the scroll view content size?
    Also, did you set the content size width to be as much as the scroll view frame width (multiplied by the number of slides like below)?

    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width * 4, self.scrollView.frame.height)
    print(self.scrollView.contentSize)

  36. Well you see problem is different. Slide width calculates properly. But
    if you try to slide manualy, scrollView doesn’t continue scrolling till
    the end of new slide.
    I tried to put slide scrolling code into
    scrollViewDidEndDecelerating but in that case only after animation is
    over (or you should touch screen again) scroll view will scroll
    properly.
    What event I should handle to catch when I take my finger out of the screen after my finger initiate scrolling?

  37. Hello Malek!
    I resolved my issue adding scrolling: paging enabled parameter

  38. Really nice tutorial, thanks!

    What if the slides are the same width but different heights? I see where to change the height of the image itself, but am unsure of how to change the scrollView height to reflect the image height. So, basically, this would be a vertical scrolling of the individual slides, with the horizontal moving between slides.

  39. Thank you for this, it’s well done.

    I have a question about different sized images being used as slides. How would one assign the scroll views of each page when that is not a constant? So that the image height will determine the height of the scroll view of each page?

  40. Hi Carolyn 🙂
    You can dynamically calculate the sum of the height of your subviews and then assign it as part of the scroll view “contentSize” property.
    Let me know if you need further help, I’ll be glad to assist!

  41. Thanks so much for the response. I’m having trouble figuring out how to assign that.

    Let’s say for those four slides that they are scrollview height, 1536, 800, scroll view height high. How can that be reflected in the contentSize property?

  42. Hi Carolyn, the content size is what counts in order for the scrollview to do paging correctly. So if you have n slide, the content size height should be (n*scrollView.frame.height). This is regardless of the images’ sizes.
    Note: I assume you want to do scroll paging vertically.

  43. I guess I’m not explaining myself well enough. I don’t want to waste your time. If you do have any to spare, what I am hoping to accomplish is to have 4 pages, which can be scrolled through horizontally, as you’ve done here. But those each page is taller than the screen size/scrollView size. I’d like each page itself to scroll vertically in order to see all the information on that page.

    So, for instance, page one. My image is 1024 x 1536. If I just leave the code as is, well, it squishes down to the size of the screen, even if I have Aspect Fit, which it’s being told to by the “let imgOne = UIImageView(frame: CGRectMake(scrollViewWidth, 0,scrollViewWidth, scrollViewHeight))”

    When I change this to “let imgOne = UIImageView(frame: CGRectMake(scrollViewWidth, 0,scrollViewWidth, 1536))”, the image displays properly, though the image is cut off. And it won’t scroll vertically.

    If in “self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.width * 4, self.scrollView.frame.height + 500)” I add a number to the scrollView frame height (in this example, 500), I can change the size of the page so vertically scrolling will take place, but this change in height is fixed across all pages.

    What is puzzling my obviously wee mind is how to tell the scrollView to programatically change the page height depending on the height of whatever image is on a given page. So instead of the scrollView.contentSize being the height of the frame of the scrollView, it’s the height of the subView image.

  44. Hi Malek! First off, thanks for the great tutorial – it’s really helpful! Is there a simple way to go about changing the text when the picture changes?

  45. Hi! What do you mean when you said you added scrolling: paging enabled parameter. I would like to do the same thing but am having trouble finding the code for this on the internet

  46. I want to run a slider on top position of app. when i use this solution its not having same offsets in landscape mode.
    Can u pls Suggest ??

  47. Hi Tyler, you just need to enable paging for the scrollview:
    self.scrollView.pagingEnabled = true
    or directly from the Attributes inspector, check the “Paging Enabled” property.

  48. WHATTT??? YOU MADE IT! Whoever made this tutorial (probably Malek??) is awesome! I just found a blog before this one and posted this comment:

    “This is cool. alextarrago, can you make a tutorial (I’ve been seeking for this for few days now) how to make a responsive UI using IB and ScrollView? I mean, for example, making a login screen, wherein you have SignIn Button, SignUp Button, Username TextField, and Password TextFields, and logo of the app as well. The challenge is that those fields should be positioned correctly even if you rotate your device and regardless what type of device you are running the app on.”

    I was going to paste this comment on this blog too but I realised that you made what I’ve been seeking for 🙁 Thank you.

  49. Great Tutorial, thank you.
    But my button is showing from the second page

  50. Thank you!! amazing tutorial…
    i have one problem.
    in iPhone 6 plus its work great but in iPhone 6 the scroll stop in the middle of the image.
    why its happening?

  51. Hi malek,

    Just wondering , I have an almost complete app I built using swift2. shouldI change it all to swift 3? is there an automated tool? and can you mix swift 2 and 3 code?

    Thanks! love your tutorials!

  52. Hi John 🙂
    Once you open your App project in Xcode 8, you should be prompted with the migration tool to Swift 3, follow the steps and your project source code will be upgraded to Swift 3 automatically. There might be some manual changes to be done though.
    Hope this helps.

  53. Hey Malek, I was trying to add additional button in my case, I want to you “Login” and “Sign Up” button appear at the last page. In other words have two buttons instead of one. My second button does not show up. Any suggestion from you?

    Thanks!!

  54. Awesome tutorial, thank you very much! I’m having an issue when turning the device from portrait to landscape, the images are not displaying in the correct size, I’m seeing two images on one screen when rotated, If I go back to the previous screen of my app, rotate to landscape then proceed to the screen that has the paging backgrounds, it works fine, but if I rotate the device back to portrait the background image shows a large gap at the bottom. How could I correct this to either: 1) Just keep the image locked in place (since it is a texture anyway) or 2) scale correctly
    Thank you in advance for any assistance you can provide.

  55. Thanks a lot
    but i have a problem that the page control is not changing after i scroll .. so that the button is not showing at the end !!
    could you help me ?

  56. Hi – I know this tutorial was a while ago, but I’m struggling to add space between views that are only visible while scrolling (like Photos app). A lot of people suggest extending the scroll view’s frame offscreen, but for me it doesn’t page the extra distance: the space ends up in the view. Any ideas?

  57. This is not working for me. The first slide works but when i swipe to the right, everything goes white. I can see that the text changes when I swipe back to the first slide. What would be causing this?

Comments are closed.