Reputation: 31
I want to make the following behavior possible in SwiftUI but i dont know how:
Imagine having a Text that contains a string (or attributed string), also you have a pointer that can be hovered over the letters of the string like a mouse icon (or any icon), as the pointer goes on a letter, that letter gets highlighted (i.e colors differently).
What i dont want: I dont want you to use different Texts and add them up using an HStack and Foreach, i want it to be all together, since i want it work for all languages and the method mentioned works for language that have unconnected letters only.
is it possible?
Upvotes: 0
Views: 142
Reputation: 66
Yes, using NSAttributedString, NSTextAttachment can achieve your needs.
I encapsulate it in HighlightWithCursorLabel
:
struct HighlightWithCursorLabel: UIViewRepresentable {
var originText: String
var color: UIColor
@Binding var highlightIndex: Int
var configuration = { (view: UILabel) in }
init(originText: String, color: UIColor, highlightIndex: Binding<Int>, configuration: @escaping (UILabel) -> () = { _ in }) {
self.originText = originText
self.color = color
self._highlightIndex = highlightIndex
self.configuration = configuration
}
func makeUIView(context: Context) -> UILabel {
let label = UILabel()
label.text = originText
label.textColor = UIColor(Colors.subText)
return label
}
func updateUIView(_ uiView: UILabel, context: Context) {
configuration(uiView)
if highlightIndex > originText.count { return }
let attributString = NSMutableAttributedString(string: originText)
let nsRange = NSRange(location: 0, length: highlightIndex)
let attribute = [NSAttributedString.Key.foregroundColor: color]
attributString.addAttributes(attribute, range: nsRange)
let attachment = NSTextAttachment(image: UIImage(systemName: "cursorarrow")!.withTintColor(color)) // replace it to any UIImage
let attachmentString = NSAttributedString(attachment: attachment)
attributString.insert(attachmentString, at: highlightIndex)
uiView.attributedText = attributString
}
}
struct HighlightSampleView: View {
@State private var highlightIndex: Int = 0
private var text = "Hello World~~~~~"
var body: some View {
HighlightWithCursorLabel(originText: text, color: UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0), highlightIndex: $highlightIndex)
.onAppear {
highlightText()
}
}
// To show the highlight effect, replace it when you want to update index
private func highlightText() {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
highlightIndex += 1
if highlightIndex > text.count {
timer.invalidate()
}
}
}
}
struct HighlightSampleView_Previews: PreviewProvider {
static var previews: some View {
HighlightSampleView()
}
}
Upvotes: 0