I'm developing a SwiftUI app, where I want to insert inline image into Text
view. For static content, I may use string interpolation like this:
Text("Hello, \(Image(systemName: "pencil")) World! \(Image(systemName: "pencil.circle"))")
The result would look like:
But in my case, the content may be dynamic. That is, I may receive the following string from server:
Hello #image(pencil) World! #image(pencil.circle)
I must parse the content dynamically and present the inline image with SwiftUI Text. Is this possible? I only wonder how to construct the string interpolation with image dynamically, the parsing of string is not my concern.
This is quite an interesting problem! Here is an alternate way of achieving this.
import SwiftUI
struct ContentView: View {
var body: some View {
let serverString = "Hello #image(pencil) World! #image(pencil.circle)"
parse(serverString).reduce(Text("")) { (result, model) in
return result + model.getSwiftUIView()
}
}
func parse(_ serverString: String) -> [Model] {
serverString.split(separator: " ", omittingEmptySubsequences: false).compactMap {
Model(word: String($0))
}
}
}
struct Model {
enum ViewType {
case image, text
}
let type: ViewType
let content: String
init(word: String) {
if word.hasPrefix("#image") {
type = .image
content = Model.replaceImagePatterns(input: String(word))
} else {
type = .text
content = word
}
}
func getSwiftUIView() -> Text {
if type == .image {
return Text("\(Image(systemName: content))") + Text(" ")
} else {
return Text(content) + Text(" ")
}
}
static func replaceImagePatterns(input: String) -> String {
let pattern = "#image\\((\\w+(?:\\.\\w+)*)\\)"
let replacement = "$1"
do {
let regex = try NSRegularExpression(pattern: pattern, options: [])
let range = NSRange(location: 0, length: input.utf16.count)
var modifiedString = input
let matches = regex.matches(in: input, options: [], range: range)
for match in matches.reversed() {
if let range = Range(match.range, in: modifiedString) {
let matchedString = String(modifiedString[range])
let modifiedMatchedString = regex.stringByReplacingMatches(in: matchedString, options: [], range: NSRange(location: 0, length: matchedString.utf16.count), withTemplate: replacement)
modifiedString = modifiedString.replacingCharacters(in: range, with: modifiedMatchedString)
}
}
return modifiedString
} catch {
print("Error creating regex: \(error)")
return input
}
}
}
Input
Hello #image(pencil) World! #image(pencil.circle)
Output
I hope you find the answer helpful.