Kyle Hobbs
Kyle Hobbs

Reputation: 457

Give SwiftUI Text view a fixed width and making text wrap to indefinite height

Major Edit to Clarify Question

What I want: For a Text view aligned to the left or right of the screen to expand to a certain maximum width and when the text reaches that length it not go beyond that. When the text to be displayed gets too long, the Text view just simply increase the height to account for the additional text. An example of this is in Apple's Messages app: Sent messages are aligned all the way to right, but even when they are very long there is still an empty space to their left (the width of the chat bubble only gets to like 75% of the screen's width).

Code I Have w/ some hardcoded values to provide example:

struct ContentView: View {
    let messages = [
        "Hello.",
        "Hi",
        "Text so long that it could reach all the way to the other side of the screen, we only want it to take up a width of about 75% of the screen though starting from the left. That is the main issue of this post.",
        "Yeah. This message is also long enough to take up the full width of the screen, but for this one we want it to take up 75% of the screen starting all the way on the right side.",
        "What are we gonna do.",
        "IDK."
    ]
    
    var body: some View {
        VStack {
            List {
                ForEach(0...5, id: \.self) { number in
                    Text(messages[number])
                        .frame(maxWidth: .infinity, alignment: number % 2 == 0 ? .leading : .trailing)

                }
            }
        }
        
    }
}

So I am almost getting what I want, every other message is right aligned. But, when the string in the Text view is long, the width of the Text view expands all the way before the height starts expanding. I'd like for the width to only expand a set amount before the height starts expanding instead.

I understand that the expansion of the width of a Text view to fit the text is normal behavior, but I'm wondering if there is a way to change that. The only thing I could think to try was changing maxWidth, however that just causes the right edge of the .trailing Text to be moved to the left which is unwanted.

Upvotes: 5

Views: 9423

Answers (3)

hamsternik
hamsternik

Reputation: 1426

Wrap your Text element into the HStack first and shrink other free space with the Spacer. Then wrap HStack container into the VStack as main content view container and apply another view modifiers, if needed.

private func textContainerView(_ copy: String) -> some View {
    VStack {
        HStack {
            Text(copy)
                .multilineTextAlignment(.leading)
                .foregroundColor(.gray)
                .font(.body)
                .padding(.all, 16)
            Spacer()
        }
    }
    .background(Color.white)
    .cornerRadius(12)
}

VStack with Text elements

Upvotes: 0

Kyle Hobbs
Kyle Hobbs

Reputation: 457

This is the code that finally worked for me. Using a fixed width Spacer rather than somehow setting a maximum width for the Text view.

var body: some View {
        VStack {
            List {
                ForEach(0...5, id: \.self) { number in
                    HStack {
                        if number % 2 != 0 {
                            Spacer()
                                .frame(minWidth: 20, maxWidth: .infinity)
                        }
                        Text(messages[number])
                        if number % 2 == 0 {
                            Spacer()
                                .frame(minWidth: 20, maxWidth: .infinity)
                        }
                    }
                }
            }
        }
        
    }

Upvotes: 1

YodagamaHeshan
YodagamaHeshan

Reputation: 6500

ForEach(previouslyPlayed, id: \.self) { data in
                Text(data.text)
                .lineLimit(nil)
                .multilineTextAlignment(.trailing)
                .foregroundColor(ColorManager.mainText)
                .font(.custom("Courier New", size: 14))
                .fixedSize(horizontal: false, vertical: true)
            }

Upvotes: 4

Related Questions