I have a SwiftUI Texteditor and whenever I press the update button the color should be applied to the text however it just gets reseted to initialValue. Can anyone help me?
import SwiftUI
class TextColorUpdater: ObservableObject {
@Published var attributedText: NSAttributedString
init(initialText: String) {
self.attributedText = TextColorUpdater.highlightText(initialText)
}
func update() {
print(attributedText.string)
self.attributedText = TextColorUpdater.highlightText(attributedText.string)
}
static func highlightText(_ text: String) -> NSAttributedString {
let mutableAttributedString = NSMutableAttributedString(string: text)
if let regex = try? NSRegularExpression(pattern: "\\bred\\b", options: .caseInsensitive) {
let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
for match in matches {
let nsRange = match.range
mutableAttributedString.addAttribute(.foregroundColor, value: UIColor.red, range: nsRange)
}
}
return mutableAttributedString
}
}
struct HighlightedTextEditor: UIViewRepresentable {
@Binding var attributedText: NSAttributedString
func makeUIView(context: Context) -> UITextView {
let textView = UITextView()
textView.isEditable = true
textView.isSelectable = true
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.attributedText = attributedText
}
}
struct ContentView: View {
@StateObject var textColorUpdater = TextColorUpdater(initialText: "This is a redd red red red car. The sky is not red")
var body: some View {
VStack {
HighlightedTextEditor(attributedText: $textColorUpdater.attributedText)
Button("Update") {
textColorUpdater.update()
}
}
}
}
When the text of UITextView
changes, you never update the @Binding
! The binding is not going to know that it is related to the UITextView
's text and update itself!
You need to detect the text change of UITextView
. You can use UITextViewDelegate
to do that. For conforming to that, you need a Coordinator
.
struct HighlightedTextEditor: UIViewRepresentable {
@Binding var attributedText: NSAttributedString
@MainActor
class Coordinator: NSObject, UITextViewDelegate {
let textView = UITextView()
var textDidChange: ((NSAttributedString) -> Void)?
override init() {
textView.isEditable = true
textView.isSelectable = true
super.init()
textView.delegate = self
}
func textViewDidChange(_ textView: UITextView) {
textDidChange?(textView.attributedText)
}
}
func makeUIView(context: Context) -> UITextView {
context.coordinator.textView
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.attributedText = attributedText
context.coordinator.textDidChange = { attributedText = $0 }
}
}