0

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)

robske_110
  • 313
  • 2
  • 8
  • Where did you try putting `.fixedSize(horizontal: false, vertical: true)`? You may need to add it to several different elements to get the layout you want. – Adam May 12 '21 at 15:31
  • I tried adding it to Text(entry.description ?? "") – robske_110 May 12 '21 at 15:52
  • I added a screenshot how it looks when I use fixedSize. Thank you for taking the time to comment :) – robske_110 May 12 '21 at 15:54
  • I don’t think you can have single divider, with what you are trying to accomplish. But, I can show you code where alignment will not be impacted, but it will use two divider line, as in your screenshot. – Tushar Sharma May 13 '21 at 07:24

2 Answers2

1

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

Tushar Sharma
  • 2,839
  • 1
  • 16
  • 38
  • Thank you! This is certainly better than the unaligned mess that resulted with the fixedSize hack. I'll implement this for now and maybe later move the description into another view that pops up when a user presses on a row. Do you think it is worth filing this as a bug with apple? I'm new in iOS app development and not quite sure if this can be considered a bug or if it's worth to bother with a bug report. But I feel the uncontrollable and inconsistent multiline behaviour is definitely not a feature. (Or at least hope so) – robske_110 May 13 '21 at 10:02
1

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

robske_110
  • 313
  • 2
  • 8