Highlight a specific part of the text in SwiftUI

Hello I’m new to Swift and am using SwiftUI for my project where I download some weather data and I display it in the ContentView().

I would like to highlight some part of the Text if it contains some specific word, but I don’t have any idea how to start.

In ContentView(), I have tried to set a function receiving the string downloaded from web and return a string. I believe this is wrong, because SwiftUI does not apply the modifiers at the all for the Text.

For example, in my ContentView() I would like the word thunderstorm to have the .bold() modifier:

struct ContentView: View {   let testo : String = "There is a thunderstorm in the area"    var body: some View {     Text(highlight(str: testo))   }    func highlight(str: String) -> String {     let textToSearch = "thunderstorm"     var result = ""      if str.contains(textToSearch) {       let index = str.startIndex       result = String( str[index])     }      return result   }  } 
Add Comment
3 Answer(s)

iOS 13, Swift 5. There is a generic solution described in this medium article. Using it you can highlight any text anywhere with the only catch being it cannot be more then 64 characters in length, since it using bitwise masks.

https://medium.com/@marklucking/an-interesting-challenge-with-swiftui-9ebb26e77376

enter image description here

This is the basic code in the article.

ForEach((0 ..< letter.count), id: \.self) { column in       Text(letter[column])         .foregroundColor(colorCode(gate: Int(self.gate), no: column) ? Color.black: Color.red)         .font(Fonts.futuraCondensedMedium(size: fontSize))      } 

And this one to mask the text…

func colorCode(gate:Int, no:Int) -> Bool {   let bgr = String(gate, radix:2).pad(with: "0", toLength: 16)  let bcr = String(no, radix:2).pad(with: "0", toLength: 16)  let binaryColumn = 1 << no - 1   let value = UInt64(gate) & UInt64(binaryColumn)  let vr = String(value, radix:2).pad(with: "0", toLength: 16)   print("bg ",bgr," bc ",bcr,vr)  return value > 0 ? true:false } 
Answered on August 31, 2020.
Add Comment

If that requires just simple word styling then here is possible solution.

Tested with Xcode 11.4 / iOS 13.4

demo

struct ContentView: View {     let testo : String = "There is a thunderstorm in the area. Added some testing long text to demo that wrapping works correctly!"       var body: some View {         hilightedText(str: testo, searched: "thunderstorm")             .multilineTextAlignment(.leading)     }      func hilightedText(str: String, searched: String) -> Text {         guard !str.isEmpty && !searched.isEmpty else { return Text(str) }          var result: Text!         let parts = str.components(separatedBy: searched)         for i in parts.indices {             result = (result == nil ? Text(parts[i]) : result + Text(parts[i]))             if i != parts.count - 1 {                 result = result + Text(searched).bold()             }         }         return result ?? Text(str)     } } 

Note: below is previously used function, but as commented by @Lkabo it has limitations on very long strings

func hilightedText(str: String) -> Text {     let textToSearch = "thunderstorm"     var result: Text!      for word in str.split(separator: " ") {         var text = Text(word)         if word == textToSearch {             text = text.bold()         }         result = (result == nil ? text : result + Text(" ") + text)     }     return result ?? Text(str) } 
Add Comment

You can concatenate with multiple Text Views.

import SwiftUI import PlaygroundSupport  struct ContentView: View {   var body: some View{     let testo : String = "There is a thunderstorm in the area"     let stringArray = testo.components(separatedBy: " ")     let stringToTextView = stringArray.reduce(Text(""), {       if $1 == "thunderstorm" {         return $0 + Text($1).bold() + Text(" ")       } else {         return $0 + Text($1) + Text(" ")       }      })     return stringToTextView   } }  PlaygroundPage.current.setLiveView(ContentView())  
Answered on August 31, 2020.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.