Reputation: 11752
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?
Upvotes: 29
Views: 27110
Reputation: 2048
You can use Text() + Text() with .reduce(), starting off with an empty Text("") variable. I you want to alternate a Text on with green and blue for subsequent words:
import SwiftUI
struct StackOverflowText: View {
let text: String
var body: some View {
let segments = text.split(separator: " ")
segments.enumerated().reduce(Text("")) { acc, pair in
acc + Text(pair.1 + " ")
.foregroundStyle(pair.0 % 2 == 0 ? .green : .blue)
}
}
}
#Preview {
StackOverflowText(text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.")
.padding()
}
Which gives you this:
Upvotes: 1
Reputation: 113
Simple solution with SwiftUI:
struct ExampleView: View {
var body: some View {
Text("\(Text("Text with blue color").coloredText(.blue)) \(Text("Text with yellow color").coloredText(.yellow))")
.padding(20)
}
}
extension Text {
func coloredText(_ color: Color) -> Text {
self.foregroundColor(color)
}
}
Upvotes: 9
Reputation: 173
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)))
}
Upvotes: 0
Reputation: 1490
If you want something like:
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)
}
Upvotes: 27
Reputation: 1782
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)
}
}
}
}
Unfortunately, this simple solution doesn't work with 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:
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.
Upvotes: 37