LoginSignup
1
1

More than 1 year has passed since last update.

【Swift】ScrollView + AutoLayout (SnapKit) での実装メモ

Posted at

はじめに

よくあるような縦方向・横方向の ScrollView の実装方法のメモ。
以下のような画面を実装します。
よければ参考にしてください。

Simulator Screen Recording - iPhone SE (2nd generation) - 2021-09-26 at 01.08.56.gif

【注意】
※ Viewはコードベースで作成しています。
※ レイアウトには SnapKit を使用しています。

環境

  • Swift5
  • Xcode13.0

実装手順

順番に実装手順を記載していきます。
ここでは、色々省略して、最低限のコードのみ記載しています。
細かいことは、記事の最後に全体のコードを載せておりますので、そちらをご参照ください。

① ScrollView を生成する。

private let scrollView: UIScrollView = {
    let scrollView = UIScrollView()
    scrollView.isPagingEnabled = false
    scrollView.showsVerticalScrollIndicator = true  // 縦方向のスクロールバーをつけるかどうか。
    // !! 横方向のスクロールバーは以下で設定する。
    // scrollView.showsHorizontalScrollIndicator = true
    return scrollView
}()

② ScrollView 内でスクロールさせるViewを生成する。(本記事では、contentView とする)

private let contentView = UIView()

③ 実際に表示したい各Viewを生成していく。(本記事では、赤色のView, 青色のView, 黄色のView が該当)

private let contentView: UIView = {
    let view = UIView()
    return view
}()

private let redView: UIView = {
    let view = UIView()
    view.backgroundColor = .red
    return view
}()

private let blueView: UIView = {
    let view = UIView()
    view.backgroundColor = .blue
    return view
}()

④ contentsView に、③で生成した View を追加して、AutoLayoutをかけていきます。
縦方向のスクロールを前提に、レイアウトをかけていきます。

contentView.addSubview(redView)
contentView.addSubview(blueView)
contentView.addSubview(yellowView)

redView.snp.makeConstraints {
    $0.top.left.right.equalToSuperview()
    $0.height.equalTo(view.frame.height)
}
blueView.snp.makeConstraints {
    $0.top.equalTo(redView.snp.bottom)
    $0.left.right.equalToSuperview()
    $0.height.equalTo(view.frame.height)
}
yellowView.snp.makeConstraints {
    $0.top.equalTo(blueView.snp.bottom)
    $0.left.right.bottom.equalToSuperview()
    $0.height.equalTo(view.frame.height)
}

⑤ scrollView に contentsView を追加して、AutoLayoutをかけていきます。

scrollView.addSubview(contentView)

contentView.snp.makeConstraints {
    $0.width.equalTo(scrollView.frameLayoutGuide) // 縦方向にスクロールさせたい場合
    // !! 横方向にスクロールしたい場合は、height に対して制約をかけます。
    // $0.height.equalTo(scrollView.frameLayoutGuide)
    $0.edges.equalTo(scrollView.contentLayoutGuide)
}

⑥ ViewController の View に ScrollView を追加して、AutoLayoutをかければ、最小限の実装は完了します。

view.addSubview(scrollView)

scrollView.snp.makeConstraints {
    $0.edges.equalTo(view.safeAreaLayoutGuide)
}

⑦ あとは適宜、調整する。

その他

横スクロールの際の、PageControl は以下で実装します。
(全体のコードを最後に記載しているのでそちらも合わせてご参照ください。)

スクリーンショット 2021-09-26 3.58.09.png

① PageControl を生成する。

private let pageControl: UIPageControl = {
    let pageControl = UIPageControl()
    pageControl.pageIndicatorTintColor = .lightGray
    pageControl.currentPageIndicatorTintColor = .black
    pageControl.numberOfPages = 3  // ページ数。(画面でいうドットの数。)
    return pageControl
}()

② ScrollView の delegete を ViewController に設定する。

private lazy var scrollView: UIScrollView = {
    let scrollView = UIScrollView()
    scrollView.delegate = self
    return scrollView
}()

③ scrollViewDidScroll(_ scrollView:) の delegateメゾットから UIPageControlを更新する。

extension HorizontalViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        pageControl.currentPage = Int(scrollView.contentOffset.x / scrollView.frame.size.width)
    }
}

全体のコード

以下に、「はじめに」に添付した Gif のコードを記載します。
GitHubはこちら

縦方向のスクロール

Simulator Screen Recording - iPhone SE (2nd generation) - 2021-09-26 at 01.08.56 (1).gif

VerticalViewController.swift
import UIKit
import SnapKit

final class VerticalViewController: UIViewController {

    private let scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.backgroundColor = .red
        return scrollView
    }()

    private let contentView: UIView = {
        let view = UIView()
        view.backgroundColor = .yellow
        return view
    }()

    private let redView: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        return view
    }()

    private let blueView: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        return view
    }()

    private let yellowView: UIView = {
        let view = UIView()
        view.backgroundColor = .yellow
        return view
    }()


    override func viewDidLoad() {

        contentView.addSubview(redView)
        contentView.addSubview(blueView)
        contentView.addSubview(yellowView)
        scrollView.addSubview(contentView)
        view.addSubview(scrollView)

        redView.snp.makeConstraints {
            $0.top.left.right.equalToSuperview()
            $0.height.equalTo(view.frame.height)
        }
        blueView.snp.makeConstraints {
            $0.top.equalTo(redView.snp.bottom)
            $0.left.right.equalToSuperview()
            $0.height.equalTo(view.frame.height)
        }
        yellowView.snp.makeConstraints {
            $0.top.equalTo(blueView.snp.bottom)
            $0.left.right.bottom.equalToSuperview()
            $0.height.equalTo(view.frame.height)
        }
        contentView.snp.makeConstraints {
            $0.width.equalTo(scrollView.frameLayoutGuide)       // 縦方向の Scroll の場合は Width に合わせる
            $0.edges.equalTo(scrollView.contentLayoutGuide)
        }
        scrollView.snp.makeConstraints {
            $0.edges.equalTo(view.safeAreaLayoutGuide)
        }
    }
}

横方向のスクロール(チュートリアル画面風)

Simulator Screen Recording - iPhone SE (2nd generation) - 2021-09-26 at 04.08.24.gif

HorizontalViewController.swift
import UIKit
import SnapKit

final class HorizontalViewController: UIViewController {

    private let headerLabel: UILabel = {
        let label = UILabel()
        label.text = "横方向の ScrollView\n(チュートリアル画面風)"
        label.numberOfLines = 0
        label.font = .systemFont(ofSize: 20)
        label.textAlignment = .center
        label.textColor = .black
        return label
    }()

    private lazy var scrollView: UIScrollView = {
        let scrollView = UIScrollView()
        scrollView.isPagingEnabled = true
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.delegate = self
        return scrollView
    }()

    private let contentView: UIView = {
        let view = UIView()
        return view
    }()

    private let redView: UIView = {
        let view = UIView()
        view.backgroundColor = .red
        return view
    }()

    private let blueView: UIView = {
        let view = UIView()
        view.backgroundColor = .blue
        return view
    }()

    private let yellowView: UIView = {
        let view = UIView()
        view.backgroundColor = .yellow
        return view
    }()

    private let pageControl: UIPageControl = {
        let pageControl = UIPageControl()
        pageControl.pageIndicatorTintColor = .lightGray
        pageControl.currentPageIndicatorTintColor = .black
        pageControl.numberOfPages = 3
        return pageControl
    }()

    override func viewDidLoad() {

        contentView.addSubview(redView)
        contentView.addSubview(blueView)
        contentView.addSubview(yellowView)
        scrollView.addSubview(contentView)
        view.addSubview(headerLabel)
        view.addSubview(scrollView)
        view.addSubview(pageControl)

        redView.snp.makeConstraints {
            $0.top.bottom.left.equalToSuperview()
            $0.width.equalTo(view.frame.width)
        }
        blueView.snp.makeConstraints {
            $0.top.bottom.equalToSuperview()
            $0.left.equalTo(redView.snp.right)
            $0.right.equalTo(yellowView.snp.left)
            $0.width.equalTo(view.frame.width)
        }
        yellowView.snp.makeConstraints {
            $0.top.bottom.right.equalToSuperview()
            $0.left.equalTo(blueView.snp.right)
            $0.width.equalTo(view.frame.width)
        }
        contentView.snp.makeConstraints {
            $0.height.equalTo(scrollView.frameLayoutGuide)       // 横方向の Scroll の場合は height を frameLayoutGuide に合わせる
            $0.edges.equalTo(scrollView.contentLayoutGuide)
        }
        headerLabel.snp.makeConstraints {
            $0.top.left.right.equalTo(view.safeAreaLayoutGuide)
            $0.height.equalTo(100)
        }
        scrollView.snp.makeConstraints {
            $0.top.equalTo(headerLabel.snp.bottom)
            $0.left.right.equalTo(view.safeAreaLayoutGuide)
            $0.bottom.equalTo(pageControl.snp.top)
        }
        pageControl.snp.makeConstraints {
            $0.top.equalTo(scrollView.snp.bottom)
            $0.left.right.bottom.equalTo(view.safeAreaLayoutGuide)
            $0.height.equalTo(15)
        }
    }
}

extension HorizontalViewController: UIScrollViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        pageControl.currentPage = Int(scrollView.contentOffset.x / scrollView.frame.size.width)
    }
}

参考にした記事

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1