[SwiftUI]ListとScrollViewはどうやって使い分ける?二つの特徴と違い

「 SwiftUIのListとScrollViewの違いって? 」

「 どちらもそんなに変わらないのでは…? 」

SwiftUIには、スクロール画面を作ることができるという点で似た性質をもつ「List」と「ScrollView」があります。

一見同じように見えるこの二つの機能ですが、データの取り扱い方やメモリの使い方に違いがあり、用途によって使い分ける必要があります。

本記事では、ListとScrollViewの異なる点に加えて、どのように使い分けたら良いかをお話していきます!

[ 本記事はこんな人におすすめ ]

・SwiftUIを学びたい

・アプリでスクロール画面を作りたい

・ListとScrollViewの使い分けを知りたい

環境・バージョン

  > Swift 5.7.2

  > Xcode 14.2

  > macOS 12.5 Monterey

1. ListとScrollViewの違い

1-1 Listの特徴

Listは縦方向にのみ、画面スクロールが可能です。

デフォルトでセパレート線(区切り線)が引かれており、要素ごとに適度な余白が設けられています。

List機能について詳しくはこちらをご覧ください。

[初心者向け]SwiftUIで一覧画面(List:リスト)を作ろう!

				
					struct ContentView: View {
    var body: some View {

        List {   // ⬅︎

            ForEach(1..<100) { index in

                Text("データ\(index)")

            } // ForEach
        } // List
    } // body
} // View

				
			
[SwiftUI]ListとScrollViewはどうやって使い分ける?二つの特徴と違い

Listのメモリ生成の特徴として、スクロールによって画面に表示されるタイミングでデータをメモリ上に生成します。

画面に表示される分だけメモリを生成するため、処理が軽いという特徴があります。

これは「遅延読み込み」とも呼ばれます。

1-2 ScrollViewの特徴

ScrollViewは縦方向だけでなく、横、斜め、全方向への画面スクロールが可能です。

要素ごとのセパレート線(区切り線)はありません。

ScrollViewについて詳しくはこちらをご覧ください。

[SwiftUI]スクロール画面を作ろう!ScrollViewの使い方

				
					struct ContentView: View {
    var body: some View {

        ScrollView { // ⬅︎

            ForEach(1..<100) { index in

                Text("データ\(index)")

            } // ForEach

        } // ScrollView
    } // body
} // View
				
			

ScrollViewのメモリ生成の特徴として、
画面表示時に、データ要素の全てをメモリ上に生成します。

一度に全てのデータを読み込むため、表示するデータ量が大きい場合は、読み込みに時間がかかる可能性があります。

2. メモリ生成のタイミングを実験

「ScrollView」と「List」では、保持しているデータのメモリ生成(インスタンス化)のタイミングが異なります。

それぞれのメモリ生成のタイミングの違いを実験してみましょう。

メモリとは

コンピュータやスマートフォンのデータを記憶する領域のこと。

メモリ領域には制限があり、メモリを過度に圧迫すると処理が重くなったり、

アプリケーションが落ちる原因になる。

2-1 子Viewを新規で作成

メモリ生成を実験するための下準備をしていきます。

新しくView構造体「RowText」を作成して、ContentView側から呼び出すコードを実装しました。

「row」とは、「1つ分、1つの」といった意味合いがあります。リスト内に表示される1つ分のテキスト要素と思っていただければ大丈夫です。

このように、Viewを呼び出す側は「親View」呼び出される側は「子View」と呼ばれます。

今回の場合、親Viewは「ContentView」、子Viewは「RowText」ですね。

				
					// 独自の子View
struct RowText: View {

    // 画面表示されるテキストが格納される
    let outputText: String

    // ② イニシャライザー(最初に動くメソッド)
    init(_ inputText: String) {
        // プリント出力
        print(inputText)
        // 親Viewから渡された「inputText」を「outputText」に格納
        outputText = inputText
    }

    var body: some View {
        // ③ テキスト表示
        Text(outputText)

    } // body
} // View

struct ContentView: View {
    var body: some View {

        List {

            ForEach(1..<100) { index in

                // ① 子Viewを呼び出し
                RowText("データ\(index)")
            }

        } // ScrollView
    } // body
} // View

				
			

コード7〜13行目、initの中でprint出力を配置しています。

「init」内のコードは、Viewが生成された時に一番最初に実行されます。

この「RowText」が親Viewからの呼び出しによって生成された時に、print出力が実行されることで、どのタイミングで子Viewがメモリ生成されたのかがわかるという仕組みです。

…大丈夫でしょうか、ついて来れてますでしょうか?

構造体(struct)の呼び出しの仕組みに慣れていないと、少し難しく感じるかもしれません。

本記事では「ListやScrollViewが表示データ分のメモリを生成した時のタイミングがわかるようにしている」ということが分かれば大丈夫です◎

では、作成した子Viewを使ってメモリ生成のタイミングを実験していきます。

2-2 Listのメモリ生成

Listは、画面上に表示されているViewのみがメモリ上に生成されます。

画面スクロールに合わせて、表示に必要な分だけ順次にメモリ生成がされるので、大量のデータでも処理が軽いという特徴があります。これを「遅延読み込み」とも呼ばれます。

				
					// 親View Listバージョン
struct ContentView: View {
    var body: some View {

        List {

           ForEach(1..<100) { index in  // ⬅︎

                // 子Viewを呼び出し
                RowText("データ\(index)")

            }

        } // ScrollView
    } // body
} // View
				
			

では、上記のコードをシミュレータ「command + R」で確認してみましょう。

[SwiftUI]ListとScrollViewはどうやって使い分ける?二つの特徴と違い

画面のスクロールに合わせて、新しく表示されるデータ範囲に合わせてメモリが生成されていることがわかります。

一度に全てのデータを読み込まず、ユーザの操作に合わせてメモリ生成する
「遅延読み込み」が確認できますね。

2-3 ScrollViewのメモリ生成

ScrollViewは、画面表示時に全てのViewがメモリ上に生成されます。

コードとしては、「List」部分を「ScrollView」に書き換えたのみです。

				
					struct ContentView: View {
    var body: some View {

        ScrollView {

            ForEach(1..<100) { index in

                // 子Viewを呼び出し
                RowText("データ\(index)")

            } // ForEzch

        } // ScrollView
    } // body
} // View
				
			

では、こちらもシミュレータ「command + R」で確認していきます。

今回はシミュレータ起動時から挙動を見てみましょう。

[SwiftUI]ListとScrollViewはどうやって使い分ける?二つの特徴と違い

シミュレータによって画面が描画された時点で、画面に表示されていない箇所も含めて、(1..<100)までの全てのデータが全てメモリ生成されていることがわかります。

ScrollViewは描画時に自身が保持するデータ全てをメモリ生成するため、たくさんのデータ数を表示するのにはあまり向かないということですね。

✅Check!!!

–  ScrollViewでも遅延読み込みが可能に  

Swiftは日々技術が刷新されています。

iOS14から、ScrollViewでも「LazyVStack」「LazyHStack」を併用することで、遅延読み込みが実装できるようになりました。

Lazyとは「怠惰」といった意味があり、遅延のニュアンスを指しています。

ScrollViewが保持しているデータを「LazyVStack」で囲みます。

				
					struct ContentView: View {
    var body: some View {

        ScrollView {

            LazyVStack {  // ⬅︎

                ForEach(1..<100) { index in
                     RowText("データ\(index)")
                 }

            } // LazyVStack
        } // ScrollView
    } // body
} // View
				
			

これによって、ScrollViewでも遅延読み込みが実装できます。

[SwiftUI]ListとScrollViewはどうやって使い分ける?二つの特徴と違い

3. ListとScrollViewの使い分け

ここまでご紹介してきた各機能を踏まえた上で、「ScrollView」と「List」をどう使い分けていくかをまとめていきます。

以下はCodeCandyのYouTube動画での参照表です。

[SwiftUI]ListとScrollViewはどうやって使い分ける?二つの特徴と違い
  • 対象アプリがどこまでのバージョンをサポートしているか
  • 表示させたいデザインやデータの見せ方(スクロール方向etc…)

これらを基準にして機能を選定しましょう。

例えば、アプリに「遅延読み込み」を実装したいとします。

iOS14以前のバージョンもサポートするアプリだった場合、前述で解説した「LazyVStack」や「LazyHStack」は使用できません。よって、「List」を用いるのが望ましいでしょう。

まとめ

以上、SwiftUIの機能「List」と「ScrollView」それぞれの特徴と使い分けについてでした。

Listは画面表示に合わせてメモリを生成する(遅延読み込み)

ScrollViewは一度に全てのデータをメモリ生成する

・LazyVStack, LazyHStackを使うことで、ScrollViewでも遅延読み込みが可能 (iOS14〜)

実装したい機能や画面デザイン、アプリの仕様に合わせて、適切に使い分けていきましょう◎

関連記事の紹介

動画の紹介

\  SHARE  /

Twitter
Facebook
Email

✏️ アプリ開発が学べる勉強会を開催中! 

CodeCandyではアプリ開発を学ぶための勉強会を定期開催しています。
学習する習慣を身につけたい、他の参加者と作業したい、アプリ開発の基本をマスターしたい、という方のために無料で学べる勉強会です。
グループにメンバー登録して頂くと、イベント開催時にメールで通知されます。

▶️グループのメンバーとして参加する

徹底した基礎学習からマスターするiPhoneアプリ開発集中オンライン講座開講!

本書「iPhoneアプリ開発集中講座」を執筆している現役エンジニア講師陣が直接に指導!
基礎、課題実習で実践力を鍛えて、オリジナルアプリ公開までチャレンジ!
充実した転職支援もあるので、エンジニアへ転職したい人にもおすすめです!

まずは、現役エンジニアに相談できる無料相談をご利用ください。

\ Official /

By 中川 賢亮

2022年2月よりSwift学習を始め、4月からiOSアプリ開発オンラインスクール「CodeCandy」にてアプリ開発を学ぶ。 2023年10月に個人開発アプリ「unico」をリリース。現在はアプリの機能アップデートをしながら、スクール運営の技術ブログの執筆や、出版書籍の入稿チェック・デバッグにも携わる。