How to embed List in ScrollView using SwiftUI

Hi! I want to allow user to scroll a long list of items iOS app, so I am trying to embbed a List view in ScrollView view. However, the preview result doesn't work. Can you help me to check what I am missing?


Below is my experimental code I entered to the file ContentView.swift, started with Single Page App project.

struct ContentView: View {
    var body: some View {
        ScrollView{
            List{
                Text("abc")
                Text("def")
            }
            .border(Color.yellow, width: 3)
            .background(Color.blue)
        }.padding(10).border(Color.red, width: 3)
    }
}


The preview of this code shows the red borders of the ScrollView, but not showing anything for the list, nor the text inside. If I change "List" to "VStack", then everything worked as expected.


I don't understand why List doesn't work, and don't know how to fix it. Can you help me to find some clue?


Thank you!

Answered by Jim Dovey in 398048022

List should already scroll—it's equivalent to UITableView. Simply remove the ScrollView and your application should work. For instance this will almost match what you've described above:


List {
    Text("abc")
    Text("def")
}
.border(Color.yellow, width: 3)
.background(Color.blue)
.padding(10)
.border(Color.red, width: 3)


Now, if your aim is to have the red border and the padding remain on screen while the list and its yellow border are scrolling, then you may have to do things a little differently. In this case, you can switch out the List with a ForEach to iterate over a collection, manually using a VStack to place a Divider view beneath each cell:


ScrollView {
    ForEach(names, id: \.self) { name in
        VStack {
            Text(name)
            Divider()
        }
    }
    .border(Color.yellow, width: 3)
    .background(Color.blue)
}
.padding(10)
.border(Color.red, width: 3)


Note that only a List will provide the appearance of 'empty' cells to fill up the screen.

Accepted Answer

List should already scroll—it's equivalent to UITableView. Simply remove the ScrollView and your application should work. For instance this will almost match what you've described above:


List {
    Text("abc")
    Text("def")
}
.border(Color.yellow, width: 3)
.background(Color.blue)
.padding(10)
.border(Color.red, width: 3)


Now, if your aim is to have the red border and the padding remain on screen while the list and its yellow border are scrolling, then you may have to do things a little differently. In this case, you can switch out the List with a ForEach to iterate over a collection, manually using a VStack to place a Divider view beneath each cell:


ScrollView {
    ForEach(names, id: \.self) { name in
        VStack {
            Text(name)
            Divider()
        }
    }
    .border(Color.yellow, width: 3)
    .background(Color.blue)
}
.padding(10)
.border(Color.red, width: 3)


Note that only a List will provide the appearance of 'empty' cells to fill up the screen.

What's your purpose in embedding a List instead of a VStack in the scrollView.


This works an scrolls:


struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                Text("abc").frame(width: 200, height: 50)
                Text("def").frame(width: 200, height: 50)
            }
            .border(Color.yellow, width: 3)
            .background(Color.blue)
        }.padding(10).border(Color.red, width: 3)
    }
}



Or simply a List, which automatically scrolls:


struct ContentView: View {
    var body: some View {
        List {
            Text("abc").frame(width: 200, height: 50)
            Text("def").frame(width: 200, height: 50)
        }.padding(10).border(Color.red, width: 3)
    }
}

Hi Jim Dovey,


You are right. I didn't realize that List can already let me scroll for the content more than one screen. The ForEach solution works for me because it seems to support more than 10 items inside.

Thank you!


struct ContentView: View {
    var body: some View {
        List {
            ForEach(1 ... 100, id: \.self ) {
                x in
                VStack {
                Text("dfsf")
                Text("sfsdfj")
                }
            }
        }.padding(10)
    }
}

Hi Claude31,


My original purpose is to display a long list of content without realizing List can already scroll. Now the problem is resolved. Thank you!

A list will scroll vertically. However, I don't see a way to get horizontal scrolling or selecting of elements within the list. Does anyone know how to do these things?

Notes has a Recently Deleted folder view that shows a search field and some captions above the list. The whole vertical stack is scrollable. That makes me think they're using UIKit and not SwiftUI.

Video

Using ForEach with a Divider won't allow .swipeActions to work, as it must be inside a List.

How to embed List in ScrollView using SwiftUI
 
 
Q