Michał Ziobro
Michał Ziobro

Reputation: 11762

SwiftUI: Text views concatenation how to do this with ForEach loop or array of strings

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"))

Upvotes: 8

Views: 5526

Answers (2)

Michał Ziobro
Michał Ziobro

Reputation: 11762

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

Upvotes: 4

LuLuGaGa
LuLuGaGa

Reputation: 14388

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(" ")} )
}

Upvotes: 30

Related Questions