0
votes

I have a Text() view inside a HStack inside of a ForEach inside of a VStack. The text can be a string of any length, and I have no control of that is put inside of it. The problem is that when you run the program, the views in the VStack overlap resulting in this jumbled mess

What I want to do is have a view that resizes its height based on the height of the multi line text view, so that the views never overlap, and always displays the entirety of the string.

Here is some code that generates the view in question:

struct ScrollingChatView: View {
    @State var model: WatchModel
    @State var messages: [DisplayableMessage] = []
    
    var body: some View {
        ScrollView {
            if (!messages.isEmpty) {
                LazyVStack {
                    ForEach(messages, id: \.sortTimestamp) { message in
                            CompactChatView(message: message)
                    }
                }.padding()
            } else {
                Text("Getting Chat...").padding()
            }

        }.onReceive(model.chatDriver.publisher) { m in
            self.messages = m
        }
    }
}
struct CompactChatView: View {
    @State var message: DisplayableMessage
    @State var stringMessage: String? = nil

    var body: some View {
        VStack(alignment: .leading) {
            HStack(alignment: .top) {
                Text(message.displayAuthor)
                    .lineLimit(1)
                    .layoutPriority(1)
                Group {
                    Text(getEmojiText(message))
                        .font(.headline)
                        .fixedSize(horizontal: false, vertical: true)
                }
                Spacer()
                Text(message.displayTimestamp)
                    .font(.subheadline)
                    .foregroundColor(Color.gray)
                    .layoutPriority(1)
            }.padding(.all, 6.0)
        }
    }

    func getEmojiText(_ item: DisplayableMessage) -> String {
        var fullMessage: String = ""
        for m in item.displayMessage {
            switch m {
            case .text(let s):
                fullMessage += s
            case .emote(_):
                print()
            }
        }

        return fullMessage
    }
}

I've tried removing .fixedSize(horizontal: false, vertical: true) from the text view, but it only makes the text cut off after one line, which is not what I want.

If you need more context, the entire project in located at: https://github.com/LiveTL/apple. We're looking at code in the macOS folder.

1

1 Answers

0
votes

You may find it useful to instead use a List() with a trailing closure like this...

List(itemList) { item in 
  Text(item)
}

This should prevent the issue you are running into when trying to display messages. For more information on lists check this out: https://developer.apple.com/documentation/swiftui/list.

You can see an example of this at 25:11 here: https://developer.apple.com/videos/play/wwdc2019/216/