21

I want to style my Text view such that string it displays has different colours for each of 2 words. I know I can just use 2 x Text with different style. But then I should keep this string words in separate state variables. But I consider whether it is possible to define different .font().foregroundColor() for different parts of string.

There are also cases when there is longer lead and we want only first sentence or first word to be bolded, and remaining text to have regular font.

Any idea how to achieve this in SwiftUI?

Michał Ziobro
  • 10,759
  • 11
  • 88
  • 143
  • 2
    You might use attributed string this link may help you - http://www.gfrigerio.com/nsattributedstring-in-swiftui/ – Siju Nov 27 '19 at 13:44
  • 3
    See also here: https://www.hackingwithswift.com/quick-start/swiftui/how-to-combine-text-views-together – koen Nov 27 '19 at 13:46
  • when you say textview do you mean the `TextEditor`? I wish to do this with that, instead of Text views – CDM social medias in bio Jan 20 '21 at 15:58
  • You can find other solution here: [https://stackoverflow.com/questions/61671313/making-parts-of-text-bold-in-swiftui](https://stackoverflow.com/questions/61671313/making-parts-of-text-bold-in-swiftui) – Tiago Mendes Dec 13 '21 at 15:14

3 Answers3

34

You can alternate formatting on a String with a ForEach loop wrapped in an HStack, although that comes with its own issues. The following code will let you conditionally apply formatting based on the word's location in the string:

struct FancyTextView: View {

    let label: String

    var splicedLabel: [String] {
        return label.split(separator: " ").map(String.init)
    }

    var body: some View {
    
        HStack {
            ForEach(0..<splicedLabel.count, id: \.self) { index in
                Text(self.splicedLabel[index])
                    .fontWeight(index.isMultiple(of: 2) ? .bold : .regular)
                    .foregroundColor(index.isMultiple(of: 2) ? .blue : .red)
            }
        }
    
    }
}

String formatting example

Unfortunately, this simple solution doesn't work with longer strings:

Poor formatting for longer strings

I thought recursion might be useful, but I couldn't think of a way to use recursion with SwiftUI's Text() + Text() syntax.

Still, you could modify the above code to only format the first word with a larger font and then you could use the Text() + Text() syntax:

First word formatting

This also removes the unpleasant formatting of the HStack and ForEach combination with text. Just change the body to the following:

Text(splicedLabel[0] + " ")
        .font(.title)
        .fontWeight(.bold)
    + Text(splicedLabel[1])

If you use this example, make sure you change the maxSplits parameter in .split() to 1 and check to make sure that there are at least two strings in the resulting array.

Lineous
  • 1,642
  • 8
  • 8
  • Is there a way to do this without `+`? In my version of XCode I get this: `Referencing operator function '+' on 'RangeReplaceableCollection' requires that 'some View' conform to 'RangeReplaceableCollection'` when trying to add two styled `Text`. Can't update XCode because old MacBook... – JakeTheSnake Jul 11 '23 at 19:18
13

If you want something like:

enter image description here

Instead of using an HStack, use the addition operator like this:

Group {
        Text("I am an ")
            .foregroundColor(Color.red) +
        Text("iOS ")
            .foregroundColor(Color.black)
            .fontWeight(.heavy) +
        Text("Developer:")
            .foregroundColor(Color.blue)
            .fontWeight(.bold)
    }
Kudos
  • 1,224
  • 9
  • 21
0

If you want to specific font and color you can use like below :

 VStack{
            Text("Your First Text")
                .font(.custom("Poppins-Medium", size: 12))
                .foregroundColor(Color(uiColor: UIColor(red: 0.631, green: 0.678, blue: 0.769, alpha: 1)))
                
            Text("Your Second Text")
                .font(.custom("Helvetica-Medium", size: 20))
                .foregroundColor(Color(uiColor: UIColor(red: 0.631, green: 0.678, blue: 0.769, alpha: 1)))
        }
yasin89
  • 103
  • 8