8

I need to concatenate Text() views in SwiftUI using + operator

I tried something like this

Text("\(feed.author?.firstName ?? "") \(feed.author?.lastName ?? "") ")
                    .font(.custom("AvenirNext-Medium", size: 15))
                    .foregroundColor(.black)


                ForEach(feed.titleChunks, id: \.self) { chunk in
                    + Text("\(chunk)")
                    .font(.custom("AvenirNext-Regular", size: 15))
                    .foregroundColor(Color("BodyText"))
                }

But it of course doesn't work. Is there a way to get array of string of unknown number of elements printed using Text so that it forms single text view in SwiftUI just like

Text("1") + Text("2") + Text("3") does?

Is there some solution to this problem. I tired static approach and it works but I do not know in advance how much Text() I have

Text("\(feed.author?.firstName ?? "") \(feed.author?.lastName ?? "") ")
                    .font(.custom("AvenirNext-Medium", size: 15))
                    .foregroundColor(.black)

                + Text("\(feed.titleChunks[0])")
                .font(.custom("AvenirNext-Regular", size: 15))
                .foregroundColor(Color("BodyText"))
                + Text("\(feed.titleChunks[1])")
                .font(.custom("AvenirNext-DemiBold", size: 15))
                .foregroundColor(Color("BodyText"))

2 Answers 2

30

ForEach quite confusigly is not a loop but a ViewBuilder

What you need is reduce. The docs describe it as:

Use the reduce(::) method to produce a single value from the elements of an entire sequence. For example, you can use this method on an array of numbers to find their sum or product.

In SwiftUI context you could use it as follows:

let words = ["This", "is", "an", "example"]

var body: some View {
    words.reduce(Text(""), { $0 + Text($1) + Text(" ")} )
}
Sign up to request clarification or add additional context in comments.

Comments

4

I found solution using method or another view and there assemble Text concatenation using var output : Text variable

  var output = Text("")

        let author = Text("\(feed.author?.firstName ?? "") \(feed.author?.lastName ?? "") ")
                    .font(.custom("AvenirNext-Medium", size: 15))
                    .foregroundColor(.black)

        output = output + author

        for chunk in feed.titleChunks {

            let chunkText : Text
            if chunk.first == "#" {
                chunkText = Text("\(chunk)")
                .font(.custom("AvenirNext-DemiBold", size: 15))
                .foregroundColor(Color("BodyText"))
            } else {
                chunkText = Text("\(chunk)")
                .font(.custom("AvenirNext-Regular", size: 15))
                .foregroundColor(Color("BodyText"))
            }

            output = output + chunkText
        }

        return output

2 Comments

Thank you for the answer! Works well for me however can you explain to me why you cannot use modifiers on the text views such as background, padding etc? Thank you
.background, .padding, etc. all return a View instead of a Text, and a View can't be concatenated onto a Text.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.