Home iOS & Swift Books Auto Layout by Tutorials

5
Scroll View Written by Libranner Santos

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

By now, you understand the power of stack views. But what options do you have when you need to create user interfaces that go beyond the screen size? Scroll views.

Scroll views allow you to expand your interfaces beyond the limits of the screen. As written in the official Apple documentation at https://apple.co/2WoN2Be:

UIScrollView: A view that allows the scrolling and zooming of its contained views.

A scroll view acts as a parent view and can contain as many views as your interface needs; they are a key component for any app that requires more space. For example, you might need more space to display parts of a form or when dealing with a significant amount of text. Or maybe your app includes a large image that users need to zoom into and some way to navigate the UI that mimics a carousel. These are all great reasons to use a scroll view, and in this chapter, you’ll learn how to use them in your app.

Working with scroll view and Auto Layout

Scroll views are different than other views when it comes to Auto Layout because you need to make two types of constraints: One that sets the x, y, width and height of the scroll view, and one that sets the x, y, width and height of the subviews in the content area. Generally, when you make constraints between the scroll view and views outside of its view hierarchy, you set the scroll view’s frame. But, when you make constraints between the scroll view and views inside of its view hierarchy, you set the frame of the subviews in the scrollable content area.

When working with scroll views, keep the following in mind:

  • You need to define both the size and position of the scroll view’s frame within its superview and the size of the scroll view’s content area.
  • To define the content area, it’s best to add a content view that’s anchored to the edges of the scroll view.
  • If you don’t want to have horizontal scrolling, make the content view’s width equal to the scroll view’s width. The same is true for vertical scrolling but using the height instead.
  • When adding content, add constraints related to the content view. If you want to create a floating effect for a view inside of the scroll view, add constraints between the target view and objects outside of the scroll view.

Adding the Options Menu to the Profile Screen

Go to the starter project, open the MessagingApp project, and build and run.

private func setupMainStackView() {
  mainStackView.axis = .vertical
  mainStackView.distribution = .equalSpacing
  mainStackView.translatesAutoresizingMaskIntoConstraints =
    false
  
  view.addSubview(mainStackView)
  
  let contentLayoutGuide = view.safeAreaLayoutGuide
  
  NSLayoutConstraint.activate([
    mainStackView.leadingAnchor.constraint(equalTo:
      contentLayoutGuide.leadingAnchor),
    mainStackView.trailingAnchor.constraint(equalTo:
      contentLayoutGuide.trailingAnchor),
    mainStackView.topAnchor.constraint(equalTo:
      contentLayoutGuide.topAnchor),
  ])
  
  setupProfileHeaderView()
  setupButtons()
}
profileHeaderView.translatesAutoresizingMaskIntoConstraints =
  false
profileHeaderView.heightAnchor.constraint(
  equalToConstant: 360).isActive = true
mainStackView.addArrangedSubview(profileHeaderView)
 setupMainStackView()

func setupButtons() {
  let buttonTitles = [
    "Share Profile", "Favorites Messages", "Saved Messages",
    "Bookmarks", "History", "Notifications", "Find Friends",
    "Security", "Help", "Logout"]
  
  let buttonStack = UIStackView()
  buttonStack.translatesAutoresizingMaskIntoConstraints = false
  buttonStack.alignment = .fill
  buttonStack.axis = .vertical
  buttonStack.distribution = .equalSpacing
  
  buttonTitles.forEach { (buttonTitle) in
    buttonStack.addArrangedSubview(
      createButton(text: buttonTitle))
  }
  
  mainStackView.addArrangedSubview(buttonStack)
  NSLayoutConstraint.activate([
    buttonStack.widthAnchor.constraint(equalTo:
      mainStackView.widthAnchor),
    buttonStack.centerXAnchor.constraint(equalTo:
      mainStackView.centerXAnchor)
  ])
}

Setting up the scroll view

Go to the top of ProfileViewController and add a new property after the mainStackView declaration. This new property will contain the Scroll View:

private let scrollView = UIScrollView()
private func setupScrollView() {
  //1
  scrollView.translatesAutoresizingMaskIntoConstraints = false
  view.addSubview(scrollView)
    
  //2
  NSLayoutConstraint.activate([
    scrollView.leadingAnchor.constraint(equalTo: 
      view.leadingAnchor),
    scrollView.trailingAnchor.constraint(equalTo: 
      view.trailingAnchor),
    scrollView.topAnchor.constraint(equalTo:
      view.safeAreaLayoutGuide.topAnchor),
    scrollView.bottomAnchor.constraint(equalTo:
      view.safeAreaLayoutGuide.bottomAnchor)
  ])
}
private func setupMainStackView() {
  mainStackView.axis = .vertical
  mainStackView.distribution = .equalSpacing
  mainStackView.translatesAutoresizingMaskIntoConstraints
    = false
  
  //1
  scrollView.addSubview(mainStackView)
  
  //2
  let contentLayoutGuide = scrollView.contentLayoutGuide
  
  NSLayoutConstraint.activate([
    //3
    mainStackView.widthAnchor.constraint(equalTo:
      view.widthAnchor),
    mainStackView.leadingAnchor.constraint(equalTo:
      contentLayoutGuide.leadingAnchor),
    mainStackView.trailingAnchor.constraint(equalTo:
      contentLayoutGuide.trailingAnchor),
    mainStackView.topAnchor.constraint(equalTo:
      contentLayoutGuide.topAnchor),
    //4
    mainStackView.bottomAnchor.constraint(equalTo:
      contentLayoutGuide.bottomAnchor)
  ])
  
  //5
  setupProfileHeaderView()
  setupButtons()
}
setupScrollView()

Using the Frame Layout Guide

Before you move on, there’s one more refactor you can do. Go to setupScrollView() and replace the implementation with this one:

private func setupScrollView() {
  scrollView.translatesAutoresizingMaskIntoConstraints = false
  view.addSubview(scrollView)
  
  //1
  let frameLayoutGuide = scrollView.frameLayoutGuide
  
  //2
  NSLayoutConstraint.activate([
    frameLayoutGuide.leadingAnchor.constraint(equalTo:
      view.leadingAnchor),
    frameLayoutGuide.trailingAnchor.constraint(equalTo:
      view.trailingAnchor),
   frameLayoutGuide.topAnchor.constraint(equalTo:
      view.safeAreaLayoutGuide.topAnchor),
    frameLayoutGuide.bottomAnchor.constraint(equalTo:
      view.safeAreaLayoutGuide.bottomAnchor)
  ])
}

Challenge

For this challenge, you’ll need to create the Settings button and add it to the scroll view. This button should appear near the bottom of the scroll view and close to the right side, but it should not be part of the stack view. For reference, here’s how it should look:

Key points

  • Constraints between a scroll view and the views outside of its view hierarchy act on the scroll view’s frame.
  • Constraints between a scroll view and views inside of its view hierarchy act on the scroll view’s content area.
  • Be extra careful when setting the size and position of your scroll view. Remember that apart from setting its size and position, you’ll have to specify a content area that will affect the way the scroll view behaves.
  • It’s strongly recommended to add a content view that acts as a container for all of the views inside of the scroll view. This makes it easier to work with a scroll view that can grow in size.
  • While working with stack views (or any views) inside of a scroll view that acts as the content area, the width and height determine if the scroll view will have vertical and horizontal scrolling.
  • Remember to use frameLayoutGuide and contentLayoutGuide when creating the constraints for scroll views.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.