Swiftで横スクロールを実装する10選の方法!初心者から上級者まで完全ガイド

Swiftでの横スクロール実装ガイドのイメージSwift
この記事は約30分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

あなたがこの記事を読んでいるということは、Swiftを使って横スクロールを実装したいと考えているのではないでしょうか。

この記事を読めば、Swiftでの横スクロールの実装方法を初心者から上級者まで詳しく学ぶことができます。

Swiftでの横スクロールの実装方法に関する10の詳細な手法とサンプルコードを用意しています。

使い方、注意点、カスタマイズ方法まで、徹底的に解説します。今後のアプリ開発がスムーズに進むように、是非このガイドを参考にしてください。

●Swiftとは

SwiftはAppleが2014年に発表した新しいプログラミング言語で、iOSやmacOSなどのアプリケーション開発に使われます。

それでは、Swiftと横スクロールの実装とはどんな関係があるのでしょうか。

○Swiftの特徴

Swiftは、安全性、パフォーマンス、そして最も現代的なプログラミング言語のデザインを持つ言語として設計されました。

Objective-Cとの互換性も考慮されており、従来のCocoaとCocoa Touchのフレームワークを活用することができます。

Swiftの主な特徴は次の通りです。

  1. 強力で直感的 – 簡潔な構文で効率的にコードを書くことができます。
  2. 安全 – 実行時エラーのリスクを減少させる設計がされています。
  3. 高速 – CやObjective-Cに匹敵する、またはそれ以上の実行速度を持っています。

Swiftのこれらの特徴は、モバイルアプリのUIやアニメーションなどの動的な振る舞いを実装する際に非常に役立ちます。

○横スクロールの役割とメリット

横スクロールは、モバイルアプリやウェブページでよく見られるUIの一つです。

主な役割としては、限られた画面スペース内で多くのコンテンツや機能を表示するために使用されます。

例えば、ニュースアプリやECサイトで様々なカテゴリーを横に並べて表示したり、写真アプリで写真を横にスクロールして閲覧する際に使用されます。

横スクロールの主なメリットは次の通りです。

  1. スペースの効率的な利用 – 縦に並べるよりも多くのコンテンツや機能を表示できます。
  2. 直感的な操作 – ユーザーは自然に左右にスワイプすることで内容を探索できます。
  3. デザインの柔軟性 – 横スクロールはデザインの幅を広げる要素としても利用できます。

Swiftを使用して横スクロールを実装する際の基本的な手法や応用的な手法を学んでいきましょう。

●基本的な横スクロールの実装

Swiftを使用して横スクロールを実装する場面は多いです。

特にモバイルデバイス上では画面が狭く、多くの情報や項目を表示する際に横スクロールは欠かせない要素となっています。

ここでは、Swiftでの基本的な横スクロールの実装方法を3つのサンプルコードを通して解説していきます。

○サンプルコード1:基本的なUIScrollViewの使用方法

UIScrollViewはiOSでスクロール可能な領域を作成するためのクラスです。

このコードでは、UIScrollViewを使って簡単な横スクロール領域を作成しています。

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        // UIScrollViewのインスタンス生成
        let scrollView = UIScrollView()
        scrollView.frame = self.view.bounds
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)
        scrollView.isPagingEnabled = true // ページごとのスクロールを有効にする
        self.view.addSubview(scrollView)

        // 3つのページを表示
        for i in 0..<3 {
            let pageView = UIView()
            pageView.frame = CGRect(x: CGFloat(i) * self.view.bounds.width, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
            pageView.backgroundColor = [UIColor.red, UIColor.green, UIColor.blue][i]
            scrollView.addSubview(pageView)
        }
    }
}

このコードを実行すると、赤、緑、青の3つのページが左から右へと横スクロールできるUIScrollViewが表示されます。

○サンプルコード2:Pagingを活用した横スクロール

Pagingを活用することで、1ページごとに内容が切り替わるようなスクロールを実現できます。

この例では、UIScrollViewのisPagingEnabledプロパティを使ってページング機能を有効にしています。

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let scrollView = UIScrollView()
        scrollView.frame = self.view.bounds
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 5, height: self.view.bounds.height)
        scrollView.isPagingEnabled = true
        self.view.addSubview(scrollView)

        let colors: [UIColor] = [.red, .blue, .yellow, .green, .orange]
        for i in 0..<5 {
            let pageView = UIView()
            pageView.frame = CGRect(x: CGFloat(i) * self.view.bounds.width, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
            pageView.backgroundColor = colors[i]
            scrollView.addSubview(pageView)
        }
    }
}

このコードを実行すると、5つのカラーページが横スクロールでき、1ページずつ内容が切り替わるような挙動を確認できます。

○サンプルコード3:CollectionViewを使った横スクロール

UICollectionViewは、グリッド表示や横スクロールなど、さまざまなレイアウトを実現するためのUI部品です。

この例では、CollectionViewを使用して横スクロール可能な領域を作成します。

import UIKit

class ViewController: UIViewController, UICollectionViewDataSource {
    let cellIdentifier = "cell"
    var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let layout = UICollectionViewFlowLayout()
        layout.itemSize = self.view.bounds.size
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0

        collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.isPagingEnabled = true
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellIdentifier)
        self.view.addSubview(collectionView)
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
        cell.backgroundColor = [UIColor.red, UIColor.green, UIColor.blue, UIColor.yellow, UIColor.purple][indexPath.item]
        return cell
    }
}

このコードを実行すると、5つの異なる色のページが左から右へと横スクロールできるUICollectionViewが表示されます。

●応用的な横スクロールの実装

Swiftでの横スクロールの基本的な実装方法を把握したところで、次はさらに応用的な横スクロールの実装について解説します。

ここでは、インタラクティブなエフェクトや縦スクロールとの組み合わせなど、より高度な実装方法を解説します。

○サンプルコード4:インタラクティブな横スクロールエフェクト

インタラクティブなエフェクトを加えることで、ユーザーがアプリを操作する際の体験を向上させることができます。

このコードでは、スクロールする速度に応じてビューのサイズが変動するエフェクトを実装しています。

import UIKit

class InteractiveViewController: UIViewController, UIScrollViewDelegate {
    let scrollView = UIScrollView()
    let imageView = UIImageView(image: UIImage(named: "sampleImage"))

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.delegate = self
        scrollView.frame = self.view.bounds
        scrollView.contentSize = imageView.bounds.size
        scrollView.addSubview(imageView)
        self.view.addSubview(scrollView)
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let offset = scrollView.contentOffset.x
        let scale = 1.0 + offset / 1000.0
        imageView.transform = CGAffineTransform(scaleX: scale, y: scale)
    }
}

このコードを実行すると、ユーザーがスクロールする速度に合わせて、イメージビューのサイズが動的に変動する効果を確認できます。

○サンプルコード5:横スクロールの中での縦スクロールの組み合わせ

特定のページ内で縦にも情報をスクロールする必要がある場合、横スクロールと縦スクロールを組み合わせることができます。

このコードでは、横スクロールする各ページに縦スクロール領域を持つ実装を行っています。

import UIKit

class CombinedViewController: UIViewController {
    let outerScrollView = UIScrollView()
    let innerScrollViews: [UIScrollView] = [UIScrollView(), UIScrollView(), UIScrollView()]

    override func viewDidLoad() {
        super.viewDidLoad()

        outerScrollView.frame = self.view.bounds
        outerScrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)
        outerScrollView.isPagingEnabled = true
        self.view.addSubview(outerScrollView)

        for i in 0..<3 {
            let innerScrollView = innerScrollViews[i]
            innerScrollView.frame = CGRect(x: CGFloat(i) * self.view.bounds.width, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
            innerScrollView.contentSize = CGSize(width: self.view.bounds.width, height: self.view.bounds.height * 2)

            let contentLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height * 2))
            contentLabel.text = String(repeating: "コンテンツ\(i + 1) ", count: 50)
            contentLabel.numberOfLines = 0
            innerScrollView.addSubview(contentLabel)

            outerScrollView.addSubview(innerScrollView)
        }
    }
}

このコードを実行すると、3ページの横スクロールがあり、各ページに縦スクロールするコンテンツエリアが存在することが確認できます。

○サンプルコード6:カスタムアニメーションを伴う横スクロール

カスタムアニメーションを横スクロールに組み込むことで、アプリケーションのユーザビリティや体験をさらに向上させることができます。

アニメーションを組み込むことで、スクロール時の動的な変化や演出を演出することができ、ユーザーの注意を引く効果も期待できます。

下記のサンプルコードでは、UIScrollViewを使用して、横スクロール時に各ページのビューがズームイン・ズームアウトするカスタムアニメーションを実装しています。

import UIKit

class AnimatedScrollViewController: UIViewController, UIScrollViewDelegate {
    var scrollView: UIScrollView!
    var pages: [UIView] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView = UIScrollView(frame: self.view.bounds)
        scrollView.delegate = self
        scrollView.isPagingEnabled = true
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)
        self.view.addSubview(scrollView)

        for i in 0..<3 {
            let pageView = UIView(frame: CGRect(x: CGFloat(i) * self.view.bounds.width, y: 0, width: self.view.bounds.width, height: self.view.bounds.height))
            pageView.backgroundColor = [UIColor.red, UIColor.green, UIColor.blue][i]
            pages.append(pageView)
            scrollView.addSubview(pageView)
        }
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let pageWidth = self.view.bounds.width
        let fractionalPage = scrollView.contentOffset.x / pageWidth
        let page = Int(round(fractionalPage))

        for (index, pageView) in pages.enumerated() {
            let distance = CGFloat(index) - fractionalPage
            let scale = 1 - 0.3 * abs(distance)
            pageView.transform = CGAffineTransform(scaleX: scale, y: scale)
        }
    }
}

このコードでは、UIScrollViewを使って横スクロールのビューを3ページ分作成しています。

それぞれのページのビューは、赤、緑、青の3色で区別しています。

スクロールが行われるたびに、scrollViewDidScrollメソッドが呼ばれ、この中で各ページのビューのスケールを動的に変更しています。

このコードを実行すると、スクロール時に中央のページのビューが最も大きく、両隣のページのビューが徐々に小さくなるアニメーションを確認することができます。

○サンプルコード7:非同期読み込みを活用したスムーズな横スクロール

高解像度の画像や大量のデータを表示する場合、すぐにデータを読み込むとスクロールがカクつくことがあります。

非同期読み込みを活用することで、メインスレッドをブロックせずにデータを読み込み、スムーズなスクロール体験を提供することができます。

下記のサンプルコードでは、非同期で画像を読み込む方法を表しています。

import UIKit

class AsyncScrollViewController: UIViewController {
    let scrollView = UIScrollView()
    let imageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.frame = self.view.bounds
        scrollView.addSubview(imageView)
        self.view.addSubview(scrollView)

        DispatchQueue.global().async {
            if let url = URL(string: "https://example.com/largeImage.jpg"),
               let data = try? Data(contentsOf: url),
               let image = UIImage(data: data) {
                DispatchQueue.main.async {
                    self.imageView.image = image
                    self.imageView.frame = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
                    self.scrollView.contentSize = image.size
                }
            }
        }
    }
}

このコードでは、URLを指定して非同期に画像データを取得し、取得が完了したらメインスレッド上で画像をUIImageViewに設定しています。

このコードを実行すると、大きな画像が非同期に読み込まれ、スクロール時にもスムーズに動作することが確認できます。

●横スクロールのカスタマイズ方法

Swiftにおける横スクロールのカスタマイズ方法は豊富です。

これにより、アプリのユーザビリティやデザインを向上させることが可能です。

ここでは、デザイン要素のカスタマイズ、ユーザーインタラクションのカスタマイズ、外部ライブラリを活用した高度なカスタマイズについて詳しく解説します。

○サンプルコード8:デザイン要素のカスタマイズ

横スクロールのデザイン要素のカスタマイズは、ユーザーにとっての視覚的な体験を向上させます。

下記のサンプルコードは、UIScrollViewのスクロールバーのデザインをカスタマイズしています。

import UIKit

class CustomDesignViewController: UIViewController {
    let scrollView = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.frame = self.view.bounds
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)

        scrollView.indicatorStyle = .white
        scrollView.showsHorizontalScrollIndicator = true
        scrollView.horizontalScrollIndicatorInsets = UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 10)

        self.view.addSubview(scrollView)
    }
}

このコードでは、UIScrollViewのスクロールバーの色を白に設定しており、また、位置の微調整も行っています。

○サンプルコード9:ユーザーインタラクションのカスタマイズ

ユーザーとのインタラクションをカスタマイズすることで、より使いやすいアプリを作成することができます。

下記のサンプルコードは、UIScrollViewのバウンス効果をオフにする方法を表しています。

import UIKit

class InteractionViewController: UIViewController {
    let scrollView = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.frame = self.view.bounds
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)

        scrollView.bounces = false

        self.view.addSubview(scrollView)
    }
}

このコードを使用すると、UIScrollViewがスクロールされたときにバウンス効果が発生しなくなります。

○サンプルコード10:外部ライブラリを活用した高度なカスタマイズ

外部ライブラリを活用することで、手軽に高度なカスタマイズを行うことができます。

下記のサンプルコードでは、CocoaPodsを利用してSwipeMenuViewControllerというライブラリを使用しています。

まず、Podfileに次のコードを追加し、pod installを実行します。

pod 'SwipeMenuViewController'

次に、Swiftのコードを実装します。

import UIKit
import SwipeMenuViewController

class SwipeMenuCustomViewController: UIViewController, SwipeMenuViewDelegate, SwipeMenuViewDataSource {
    var swipeMenuView: SwipeMenuView!
    var content: [UIViewController] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        let options = SwipeMenuViewOptions()
        options.tabView.style = .segmented
        options.tabView.margin = 8.0

        swipeMenuView = SwipeMenuView(frame: view.bounds, options: options)
        swipeMenuView.delegate = self
        swipeMenuView.dataSource = self
        view.addSubview(swipeMenuView)

        let firstVC = UIViewController()
        firstVC.view.backgroundColor = .red
        content.append(firstVC)

        let secondVC = UIViewController()
        secondVC.view.backgroundColor = .green
        content.append(secondVC)

        swipeMenuView.reloadData()
    }

    func numberOfPages(in swipeMenuView: SwipeMenuView) -> Int {
        return content.count
    }

    func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController {
        return content[index]
    }
}

このコードにより、タブ付きの横スクロールメニューを実装することができます。

●横スクロール実装時の注意点と対処法

Swiftで横スクロールを実装する際には、パフォーマンスやユーザビリティを確保するため、いくつかの注意点と対処法を心掛ける必要があります。

これらを適切に処理することで、ユーザーにとって快適なスクロール体験を提供できます。

○パフォーマンスの最適化

横スクロールのスムーズな動作は、アプリの品質を大きく左右します。

パフォーマンスの低下を防ぐため、サンプルコードで表すように、非同期処理やキャッシュの利用を考慮すると良いでしょう。

import UIKit

class ScrollPerformanceViewController: UIViewController {
    let scrollView = UIScrollView()
    var images: [UIImage] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.frame = self.view.bounds
        self.view.addSubview(scrollView)

        DispatchQueue.global().async {
            self.images = self.loadImages() 

            DispatchQueue.main.async {
                self.setupScrollViewImages()
            }
        }
    }

    func loadImages() -> [UIImage] {
        // 画像の読み込み処理
        // 注意: 実際のコードでは、適切に画像を読み込むコードを記述してください
        return [UIImage(named: "image1")!, UIImage(named: "image2")!]
    }

    func setupScrollViewImages() {
        for i in 0..<images.count {
            let imageView = UIImageView(image: images[i])
            imageView.frame = CGRect(x: CGFloat(i) * self.view.bounds.width, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
            scrollView.addSubview(imageView)
        }

        scrollView.contentSize = CGSize(width: self.view.bounds.width * CGFloat(images.count), height: self.view.bounds.height)
    }
}

このコードでは、DispatchQueue.global().asyncを用いて、非同期処理で画像の読み込みを行っています。

これにより、UIがフリーズすることなく、スムーズなユーザ体験を提供できます。

○メモリ管理の工夫

多数のコンテンツを横スクロールで表示する場合、メモリの消費が問題となることがあります。

下記のサンプルコードは、表示中の画面に応じて動的にコンテンツをロード・アンロードする方法を表しています。

import UIKit

class MemoryManagementViewController: UIViewController, UIScrollViewDelegate {
    let scrollView = UIScrollView()
    var content: [UIViewController] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        setupScrollView()

        content = createContent()

        loadVisibleContent()
    }

    func setupScrollView() {
        scrollView.frame = self.view.bounds
        scrollView.delegate = self
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)
        self.view.addSubview(scrollView)
    }

    func createContent() -> [UIViewController] {
        // コンテンツの生成
        return [UIViewController(), UIViewController(), UIViewController()]
    }

    func loadVisibleContent() {
        let pageWidth = scrollView.frame.size.width
        let page = Int(floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)

        loadPage(page: page - 1)
        loadPage(page: page)
        loadPage(page: page + 1)
    }

    func loadPage(page: Int) {
        if page < 0 || page >= content.count {
            return
        }

        if content[page].view.superview == nil {
            content[page].view.frame = CGRect(x: CGFloat(page) * scrollView.frame.size.width, y: 0, width: scrollView.frame.size.width, height: scrollView.frame.size.height)
            scrollView.addSubview(content[page].view)
        }
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        loadVisibleContent()
    }
}

○ユーザビリティの向上

横スクロールの実装において、ユーザビリティも重要な要素です。

下記のコードは、スクロールの方向を制限して、ユーザーの操作をより直感的にするものです。

import UIKit

class UsabilityViewController: UIViewController {
    let scrollView = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()

        scrollView.frame = self.view.bounds
        scrollView.contentSize = CGSize(width: self.view.bounds.width * 3, height: self.view.bounds.height)
        scrollView.isDirectionalLockEnabled = true
        self.view.addSubview(scrollView)
    }
}

isDirectionalLockEnabledプロパティをtrueに設定することで、スクロールの方向を一方向に制限し、ユーザーの操作を直感的にします。

まとめ

Swiftでの横スクロール実装は、アプリのユーザビリティや見た目の魅力を大きく向上させる要素の一つです。

基本的な実装から高度なカスタマイズ、さらにはパフォーマンスやメモリ管理などのテクニカルな面まで、多岐にわたる知識とテクニックが求められます。

本ガイドを通して、Swiftを使用した横スクロールの実装手法やそのカスタマイズ方法、さらには実装時の注意点などを詳しく解説しました。

初心者の方から上級者の方まで、Swiftにおける横スクロールの実装を行う際の参考として、本ガイドを活用いただければと思います。

正確な知識と実践を通して、ユーザーにとって快適なスクロール体験を提供するアプリケーションを開発しましょう。