16

I have added a List inside the ScorllView but it's not showing in canvas after adding inside to ScrollView

here is my code

struct ContentView: View {
    var body: some View {
        ScrollView {
            VStack {
                Text("My List")
                    .font(.largeTitle)
                    .fontWeight(.bold)

                List(0 ..< 5) { item in
                    Text("Hello World")
                }
            }
        }
    }
}

sw

3
  • Why are you doing this at first place ? What are you trying to achieve? Commented Nov 20, 2019 at 22:13
  • @MojtabaHosseini This is just a sample app I have created, We can also add few other View inside the VStack My concern is in storyboard we can achieve this but why can't in SwiftUI Commented Nov 21, 2019 at 3:46
  • I know, I just wanted to know how you like to see the list? fill? fit? custom? I have covered all of them in my answer, check it out. Commented Nov 21, 2019 at 7:59

3 Answers 3

26

The Issue:

That is because List infer it size from its parent View. So when you embed it inside something like VStack that have dynamic height, it can't infer it size correctly.

Solutions:

You have some options here:

1. Size List to match it's content Automatically (Perfect)

You can use ForEach directly instead of using List, then you have more control over the content size

ForEach(0 ..< 5) { item in
    VStack(alignment: .leading) {
        Text("Hello World").frame(height: 42)
        Divider()
    }
    .padding(.horizontal, 8)
}

You can change all sizes and spacings according to your needs


2. Size List to match it's content manually (Good but not perfect)

Give it a static frame like the way you do in UIKit by setting the .frame() modifier on the List:

List(0 ..< 5) { item in
    Text("Hello World")
}
.frame(height: 224)

You can use GeometryReader to find the exact size of the parent and apply it to the List


3. Just show the List (Not good but it works)

add .scaledToFill() modifier to List

Sign up to request clarification or add additional context in comments.

2 Comments

I am using scaledToFill and it works fine. Why is not considered "good?
How can scaledToFill be combined with a list where scrolling is disabled? The list is visible, but not at full height.
9

I assume you expected the following:

var body: some View {
    GeometryReader { geometry in
        ScrollView {
           VStack {
               Text("My List")
                   .font(.largeTitle)
                   .fontWeight(.bold)

                List {
                    ForEach(0 ..< 50) { item in // 50 for testing
                        Text("Hello World")
                    }
                }
            }
            .frame(height: geometry.size.height)
        }
    }
}

Comments

1

There are many reasons, why you might need a List in a ScrollView. Mine is, that I have a form, where one of the rows is a grid of images, each with a contextMenu. ContextMenu does not work in a List Row with grid content. So, this row can not be in a List. And I have other rows, where I need swipe actions. Which do not work outside of the List. That's why I have to use a List, within a ScrollView. Combining these responses https://stackoverflow.com/a/68789867/1379833, https://stackoverflow.com/a/60758138/1379833 with GeometryReader I got it to work.

import Introspect

@State private var tableViewContentHeight: CGFloat = 0

var body: some View {
    GeometryReader { screenGeometryReader in
        ScrollView {
            ... // content of the scrollView
            List {
                ... // content of the list
            }
            .introspectTableView { tableView in
                tableViewContentHeight = tableView.contentSize.height
            }
            .frame(
                width: screenGeometryReader.size.width, 
                height: tableViewContentHeight
            )
        }
    }
}

3 Comments

Introspect is a 3rd party library from github.com/siteline/SwiftUI-Introspect
This is not working.
This has stopped working in Xcode 14 :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.