How to embed a List in a ScrollView (SwiftUI)

  Kiến thức lập trình

My first attempt

I’m trying to embedding a List in a ScrollView. Like the code right below.

import SwiftUI

struct ContentView: View {
    let columns = [
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
    ]

    var body: some View {
        ScrollView {
            myGrid
            
            myList // List is not showing up on the screen
        }
    }

    var myGrid: some View {
        LazyVGrid(columns: columns, spacing: 16) {
            ForEach(0 ..< 10) { index in
                Text("Row (index)")
                    .contextMenu(ContextMenu(menuItems: {
                        Text("Menu Item 1")
                        Text("Menu Item 2")
                        Text("Menu Item 3")
                    }))
            }
        }
    }
    
    var myList: some View {
        List {
            ForEach(0 ..< 5) { index in
                Text("Row (index)")
                    .contextMenu(ContextMenu(menuItems: {
                        Text("Menu Item 1")
                        Text("Menu Item 2")
                        Text("Menu Item 3")
                    }))
            }
        }
    }
}

Result of my code

My second attempt

I want to place a List within a ScrollView to enable scrolling for the entire screen, as I am using a LazyVGrid. However, my attempt to embed the LazyVGrid in a List did not produce the desired result. When I interact with buttons or items in the LazyVGrid, the entire row in the List is affected unexpectedly.

import SwiftUI

struct ContentView: View {
    let columns = [
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
    ]

    var body: some View {
        List {
            /* this not a good solution all LazyVGrid should be outside of the List
             at the same time I can't select item seperately, all section is affected by context menu
             */
            LazyVGrid(columns: columns, spacing: 16) {
                Section {
                    ForEach(0 ..< 10) { index in
                        Text("Row (index)")
                            .contextMenu(ContextMenu(menuItems: {
                                Text("Menu Item 1")
                                Text("Menu Item 2")
                                Text("Menu Item 3")
                            }))
                    }
                }
            }
            
            ForEach(0 ..< 5) { index in
                Text("Row (index)")
                    .contextMenu(ContextMenu(menuItems: {
                        Text("Menu Item 1")
                        Text("Menu Item 2")
                        Text("Menu Item 3")
                    }))
            }
        }
    }
}

Result of the second code

My third attempt

I’m facing an issue when applying a fixed frame to a List. It doesn’t adjust dynamically based on its content. As I add more items, I find myself needing to manually increase the frame size of the list.

import SwiftUI

struct ContentView: View {
    let columns = [
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
        GridItem(.flexible(minimum: 50, maximum: 100), spacing: 16),
    ]

    var body: some View {
        ScrollView {
            myGrid
            
            /* when I set the frame, it is showing up on the screen
             but now frame is not dynamic. When I try to add more items it should be
             increased automatically. I don't know how to handle it.
             */
            myList
                .frame(width: 400, height: 400)
        }
    }

    var myGrid: some View {
        LazyVGrid(columns: columns, spacing: 16) {
            ForEach(0 ..< 10) { index in
                Text("Row (index)")
                    .contextMenu(ContextMenu(menuItems: {
                        Text("Menu Item 1")
                        Text("Menu Item 2")
                        Text("Menu Item 3")
                    }))
            }
        }
    }
    
    var myList: some View {
        List {
            ForEach(0 ..< 5) { index in
                Text("Row (index)")
                    .contextMenu(ContextMenu(menuItems: {
                        Text("Menu Item 1")
                        Text("Menu Item 2")
                        Text("Menu Item 3")
                    }))
            }
        }
    }
}

Result of the third code

Note:
I removed all styling code to simplify the amount of code.

4

LEAVE A COMMENT