I have a custom modifier which is only used on a Text view. I want to include an underline call in it, but get an error. My understanding is that this is because underline is unique to Text views whereas the ViewModifier protocol isn't.
Is there a way to specify this?
struct activeEquationString: ViewModifier {
let termInd: Int
@Binding var currentInd: Int
func body(content: Content) -> some View {
content
.underline(currentInd == termInd) // <-- Value of type 'activeEquationString.Content' (aka '_ViewModifier_Content<activeEquationString>') has no member 'underline'
.foregroundColor(currentInd == termInd ? Color.black : Color.gray)
}
}
As far as I tried, I could not write a ViewModifier with its Content constrained to Text.
ViewModifier.Content is an opaque type and we do not have much control on it.
Instead, you can define your own TextModifier protocol.
protocol TextModifier {
associatedtype Body: View
func body(text: Text) -> Body
}
extension Text {
func modifier<TM: TextModifier>(_ theModifier: TM) -> some View {
return theModifier.body(text: self)
}
}
And define a type conforming to the protocol.
struct ActiveEquationString: TextModifier {
let termInd: Int
@Binding var currentInd: Int
func body(text: Text) -> some View {
return text
.underline(currentInd == termInd)
.foregroundColor(currentInd == termInd ? Color.black : Color.gray)
}
}
You can use it in a way very similar to ViewModifier.
struct ContentView: View {
@State var ind: Int = 1
var body: some View {
VStack {
Text("Hello!\(ind)")
.modifier(ActiveEquationString(termInd: 0, currentInd: $ind))
Button(action: {
self.ind = (self.ind + 1) % 3
}) {
Text("Change ind")
}
}
}
}
In a simple example as shown above, it works as expected.