Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Geometry Reader within a ScrollView is causing items to overlap

I want to be able to show an array of notes in a ScrollView. Each of these objects contains a GeometryReader, and I'm having trouble setting each of these object's height by the amount of content that is in it.

I've made a reproducible example below (I know in this example it doesn't make sense why I need the geometry reader but I do need it in my actual app).

import SwiftUI

struct ContentView: View {
    var body: some View {
        ScrollView {
            ForEach(notes) { note in
                NoteView(note: note)
            }
        }
    }
}

struct NoteView: View {
    var note: Note = notes[0]
    
    var body: some View{
        GeometryReader { geo in
            Text(note.content)
                .fixedSize(horizontal: false, vertical: true)
                .frame(width: geo.size.width)
        }
    }
}


struct Note: Identifiable {
    var id = UUID()
    var content: String = ""
}

var notes = [
    Note(content: "Lorem ipsum dolor sit amet, consectet adipiscing elit. Condimentum quisque id vitae convallis dignissim pharetra nisl est creatus"),
    Note(content: "Mauris ac tempor libero, non eleifend lectus. Mauris eu hendrerit nunc. Donec at ante mauris. Duis ac elit purus. Mauris ullamcorper mi."),
    Note(content: "Lorem ipsum dolor sit amet, consectet adipiscing elit. Condimentum quisque id vitae convallis dignissim pharetra nisl est creatus"),
    Note(content: "Mauris ac tempor libero, non eleifend lectus. Mauris eu hendrerit nunc. Donec at ante mauris. Duis ac elit purus. Mauris ullamcorper mi.")
]

When I use embed the ForEach loop in a ScrollView all of the items overlap: Items overlapping when using ScrollView

But if I change the ScrollView to a VStack, I get more what I am looking for with the items appearing stacked on top of each other.

VStack allows the correct height of the object

I believe that overlapping is because the height of the GeometryReader is less than the height of the Text within the GeometryReader.

If I manually add .frame(height: 100) to the GeometryReader, the objects no longer overlap. But I do not know how I could create a variable for the height that would be based on the amount of Text each note contains.

like image 376
Hal219 Avatar asked Oct 17 '25 17:10

Hal219


2 Answers

Try with frame() Example :

Text(myText).frame(height: 100)

Hope it will work.

Edit: i just suggested you to use frame() Height or width fully depends on you. You may use your dynamic value by replacing height:100 Hope this make sense. Thanks

like image 74
Al Mustakim Avatar answered Oct 20 '25 08:10

Al Mustakim


It seems all texts are shown on screen but problem occurs because of GeometryReader.

I have a solution for you. If all texts are shown on screen with their all height we can get that height with adding a background modifier to all of them. And inside that background we can add another GeometryReader to get that background height.

struct NoteView: View {
    let note: Note
    @State private var height: CGFloat = 0
    
    var body: some View{
        GeometryReader { geo in
            Text(note.content)
                .fixedSize(horizontal: false, vertical: true)
                .background {
                    GeometryReader { proxy in
                        Text("")
                            .onAppear {
                                self.height = proxy.size.height
                            }
                    }
                }
        }
        .frame(height: self.height)
    }
}
like image 20
Gorkem Sevim Avatar answered Oct 20 '25 07:10

Gorkem Sevim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!