robske_110
robske_110

Reputation: 343

Multiline text truncated in ScrollView

I'm having a rather peculiar issue with multiline texts inside a ScrollView. I have a LazyVStack in the ScrollView and have SomeRow (see below) Views inside this stack. I have a long multiline description inside this SomeRow View that SwiftUI always cuts off.

I have tried all of the solutions here but they either broke the layout, didn't work or straight up caused the app to crash.

How it looks at the moment: 2

I've tried to reduce the reproducing code down to a minimum, but it is unfortunately still quite long, because I want to preserve what look I am trying to accomplish.

Here is the SomeListView:

import SwiftUI

struct SomeListView: View {
    
    var body: some View {
        VStack{
            Text("Title")
                .font(.title)
            ScrollView{
                LazyVStack{
                    ForEach(0..<4){_ in
                        SomeRow(entries: EntryContainer(entries:
                            [
                                Entry("DESC\nLONG DESCRIPTION WITH OVERFLOW"),
                                Entry("")
                            ]
                        ))
                        Spacer().frame(height: 5)
                        Divider()
                    }
                }
            }.padding(16)
        }
    }
}

struct SomeListView_Previews: PreviewProvider {
    static var previews: some View {
        SomeListView()
    }
}

SomeRow View

import SwiftUI

struct SomeRow: View {
    var entries: [Entry]
    
    var body: some View {
        VStack(alignment: .leading, spacing: 0){
            Text("title").frame(maxWidth: .infinity, alignment: .leading)
            Spacer().frame(height: 5)
            ForEach(entries){entry in
                HStack{
                    VStack{
                        Text("00:00 - 00:00")
                        Spacer()
                    }.frame(minWidth: 110)
                    Divider()
                    VStack{
                        HStack{
                            Text("titleinner")
                            Spacer()
                        }
                        HStack{
                            Text(entry.description ?? "")
                            Spacer()
                            VStack{
                                Spacer()
                                Text("number")
                            }
                        }
                        Spacer()
                    }
                    Spacer()
                }
            }
        }
    }
}

struct SomeRow_Previews: PreviewProvider {
    static var previews: some View {
        SomeRow(entries:
            [
                Entry("DESC\nLONG DESCRIPTION WITH OVERFLOW"),
                Entry("")
            ]
        )
    }
}

Entry Data Class

import Foundation

class Entry: Identifiable {
    let description: String?

    init(_ description: String? = nil) {
        self.description = description
    }
}

Any ideas for a workaround? I am assuming this is simply SwiftUI bug because if you set the same long description for both entries it magically shows both descriptions fully, which really doesn't make sense to me.

This is how it breaks when I use Text(entry.description ?? "").fixedSize(horizontal: false, vertical: true: enter image description here (The divider doesn't fill the full height anymore and alignment of the timestamps in the left column is wrong)

Upvotes: 0

Views: 981

Answers (2)

robske_110
robske_110

Reputation: 343

With the help of concepts from the answer from Tushar Sharma I was able to create a version that displays the multiline text and has a continuous divider between the two "columns". The only changes are in SomeRow View (compared to my initial question):

struct SomeRow: View {
    var entries: [Entry]
    
    var body: some View {
        VStack(alignment: .leading, spacing: 0){
            Text("title").frame(maxWidth: .infinity, alignment: .leading)
            Spacer().frame(height: 5)
            ForEach(entries){entry in
                HStack(alignment: .top){
                    VStack{
                        Text("00:00 - 00:00")
                        Spacer()
                    }.frame(minWidth: 110)
                    Divider()
                    VStack(alignment: .leading){
                        Text("titleinner")
                        HStack(alignment: .lastTextBaseline){
                            Text(entry.description ?? "")
                            Spacer()
                            Text("number")
                        }
                        Spacer()
                    }
                    Spacer()
                }.fixedSize(horizontal: false, vertical: true)
            }
        }
    }
}

Basically using specified alignments and using fixedSize on the whole container of the text works wonders. This is how it looks like now: somelistview

Upvotes: 2

Tushar Sharma
Tushar Sharma

Reputation: 2882

It’s nearly impossible to have single divider and maintain the same alignment as you are looking for. The closest I could get you is shown in below code. Hope it satisfies requirement to some extent.

   import SwiftUI

struct SomeListView: View {
    var obj = [
        Entry("DESC LONG DESCRIPTION WITH OVERFLOW"),
        Entry("")
    ]
    var body: some View {
        
        VStack{
            Text("Title")
                .font(.title)
            ScrollView{
                
                LazyVStack(){
                    ForEach(0..<4){_ in
                        SomeRow(entries: obj)
                        Spacer().frame(height: 5)
                        Divider()
                    }
                }
            }.padding(16)
        }
        
    }
}


class Entry: Identifiable {
    let description: String?
    
    init(_ description: String? = nil) {
        self.description = description
    }
}

struct SomeRow: View {
    var entries: [Entry]
    
    var body: some View {
        
        VStack(alignment: .leading,spacing:7){
            
            Text("title")
            
            ForEach(entries){entry in
                
                HStack(alignment: .top,spacing:15){
                    
                    Text("00:00 - 00:00")
                    Divider()
                    VStack(alignment:.leading, spacing:8){
                        Text("titleinner")
                        HStack(alignment:.lastTextBaseline, spacing:0){
                            Text(entry.description ?? "")
                            Spacer()
                            Text("number")
                        }
                        
                    }
                }.fixedSize(horizontal: false, vertical: true)
            }
        }
    }
}

struct SomeRow_Previews: PreviewProvider {
    static var previews: some View {
        SomeRow(entries:
                    [
                        Entry("DESC\nLONG DESCRIPTION WITH OVERFLOW"),
                        Entry("")
                    ]
        )
    }
}

struct SomeListView_Previews: PreviewProvider {
    static var previews: some View {
        SomeListView()
    }
}

Output-:

enter image description here

Upvotes: 1

Related Questions