Vaz*_*Vaz 5 text hyperlink underline swift swiftui
在 SwiftUI 中,如果我在字符串之间有一个网络链接,我如何创建一个超链接并在我的视图中为其添加下划线。
请注意,“messageContent”字符串并不总是相同。
例如
struct MessageModel {
var messageContent: String = "Test of hyperlink www.google.co.uk within a text message"
}
struct Content: View {
var message: MessageModel
var body: some View {
VStack {
Text(message.messageContent)
}
}
}
Run Code Online (Sandbox Code Playgroud)
该图片显示了我想要实现的目标。“www.google.co.uk”是一个可点击的超链接,带有下划线
更新我正在努力实现的目标
我创建了下面的测试代码来展示我想要实现的目标,因为如上所述,“messageContent”并不总是相同的字符串。
虽然下面的内容并不完美地处理所有情况和处理错误等,但希望这能更好地了解我想要实现的目标。唯一的麻烦是这似乎不起作用。
它为超链接生成下划线,但文本不会以 Markdown 格式显示 - 请参阅附图。
import SwiftUI
struct HyperlinkAndUnderlineText: View {
var message: MessagesModel = MessagesModel(messageContent: "Test of hyperlink www.google.co.uk within a text message")
@State var messageContentAfterSplitting: [SplitMessage] = []
var body: some View {
CustomText(inputText: messageContentAfterSplitting)
.onAppear() {
messageContentAfterSplitting = splitMessage(message: message)
}
}
}
struct MessagesModel {
var messageContent: String = ""
}
struct SplitMessage {
var content: String = ""
var type: contentType = .text
}
enum contentType {
case text
case url
}
func splitMessage(message: MessagesModel) -> [SplitMessage] {
func detectIfMessageContainsUrl(message: String) -> [String]? {
let urlDetector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = urlDetector.matches(in: message, options: [], range: NSRange(location: 0, length: message.utf16.count))
var urls: [String] = []
for (index, match) in matches.enumerated() {
guard let range = Range(match.range, in: message) else { continue }
let url = message[range]
urls.append(String(url))
if index == matches.count - 1 {
return urls
}
}
return []
}
let urlsFoundInMessage = detectIfMessageContainsUrl(message: message.messageContent)
func getComponents(urlsFoundInMessage: [String]) -> [String] {
var componentsEitherSideOfUrl: [String] = []
for (index,url) in urlsFoundInMessage.enumerated() {
componentsEitherSideOfUrl = message.messageContent.components(separatedBy: url)
if index == urlsFoundInMessage.count - 1 {
return componentsEitherSideOfUrl
}
}
return []
}
let componentsEitherSideOfUrl = getComponents(urlsFoundInMessage: urlsFoundInMessage!)
func markdown(urlsFoundInMessage: [String]) -> [String] {
var markdownUrlsArray: [String] = []
for (index, url) in urlsFoundInMessage.enumerated() {
let placeholderText = "[\(url)]"
var url2: String
if url.hasPrefix("https://www.") {
url2 = "(\(url.replacingOccurrences(of: "https://www.", with: "https://")))"
} else if url.hasPrefix("www.") {
url2 = "(\(url.replacingOccurrences(of: "www.", with: "https://")))"
} else {
url2 = "(\(url))"
}
let markdownUrl = placeholderText + url2
markdownUrlsArray.append(markdownUrl)
if index == urlsFoundInMessage.count - 1 {
return markdownUrlsArray
}
}
return []
}
let markdownUrls = markdown(urlsFoundInMessage: urlsFoundInMessage!)
func recombineStrings(componentsEitherSideOfUrl: [String], markdownUrls: [String]) -> [SplitMessage] {
var text = SplitMessage()
var textAsArray: [SplitMessage] = []
for i in 0...2 {
if i.isMultiple(of: 2) {
if i == 0 {
text.content = componentsEitherSideOfUrl[i]
text.type = .text
textAsArray.append(text)
} else {
text.content = componentsEitherSideOfUrl[i-1]
text.type = .text
textAsArray.append(text)
}
} else {
text.content = markdownUrls[i-1]
text.type = .url
textAsArray.append(text)
}
}
return textAsArray
}
let recombinedStringArray = recombineStrings(componentsEitherSideOfUrl: componentsEitherSideOfUrl, markdownUrls: markdownUrls)
return recombinedStringArray
}
func CustomText(inputText: [SplitMessage]) -> Text {
var output = Text("")
for input in inputText {
let text: Text
text = Text(input.content)
.underline(input.type == .url ? true : false, color: .blue)
output = output + text
}
return output
}
Run Code Online (Sandbox Code Playgroud)
在 Swift 5.5(iOS 15+)中
您可以使用降价:
Text("This is a link [Google](https://google.com.com)")
Run Code Online (Sandbox Code Playgroud)
要仅向链接添加下划线,您可以这样做:
Text("This is a link ") + Text("[google.com](https://google.com.com)").underline()
Run Code Online (Sandbox Code Playgroud)
这是我使用的最终解决方案。应该适用于各种字符串输入。
import SwiftUI
struct HyperlinkAndUnderlineTextView: View {
var body: some View {
ScrollView {
VStack (alignment: .leading, spacing: 30) {
Group {
CustomTextWithHyperlinkAndUnderline("Test of a hyperlink www.google.co.uk within a text message", .blue)
CustomTextWithHyperlinkAndUnderline("www.google.co.uk hyperlink at the start of a text message", .blue)
CustomTextWithHyperlinkAndUnderline("Test of hyperlink at the end of a text message www.google.co.uk", .blue)
CustomTextWithHyperlinkAndUnderline("www.google.co.uk", .blue)
CustomTextWithHyperlinkAndUnderline("This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink www.apple.com", .blue)
CustomTextWithHyperlinkAndUnderline("This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink www.apple.com. This is text after it.", .blue)
CustomTextWithHyperlinkAndUnderline("This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink www.apple.com. This is a 3rd hyperlink www.microsoft.com", .blue)
CustomTextWithHyperlinkAndUnderline("This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink www.apple.com. This is a 3rd hyperlink www.microsoft.com. This is text after it.", .blue)
CustomTextWithHyperlinkAndUnderline("www.google.co.uk is a hyperlink at the start of a text message. www.apple.com is the 2nd hyperlink within the same text message.", .blue)
CustomTextWithHyperlinkAndUnderline("This is a test of another type of url which will get processed google.co.uk", .blue)
}
Group {
CustomTextWithHyperlinkAndUnderline("google.co.uk", .blue)
CustomTextWithHyperlinkAndUnderline("Pure text with no hyperlink", .blue)
CustomTextWithHyperlinkAndUnderline("Emoji test ", .blue)
}
}
}
}
}
struct SplitMessageContentWithType {
var content: String = ""
var type: contentType = .text
}
enum contentType {
case text
case url
}
//Function to produce a text view where all urls and clickable and underlined
func CustomTextWithHyperlinkAndUnderline(_ inputString: String, _ underlineColor: Color) -> Text {
let inputText: [SplitMessageContentWithType] = splitMessage(inputString)
var output = Text("")
for input in inputText {
let text: Text
text = Text(.init(input.content))
.underline(input.type == .url ? true : false, color: underlineColor)
output = output + text
}
return output
}
func splitMessage(_ inputString: String) -> [SplitMessageContentWithType] {
//1) Function to detect if the input string contains any urls and returns the ones found as an array of strings
func detectIfInputStringContainsUrl(inputString: String) -> [String] {
let urlDetector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
let matches = urlDetector.matches(in: inputString, options: [], range: NSRange(location: 0, length: inputString.utf16.count))
var urls: [String] = []
for match in matches {
guard let range = Range(match.range, in: inputString) else { continue }
let url = inputString[range]
urls.append(String(url))
}
return urls
}
let urlsFoundInInputString = detectIfInputStringContainsUrl(inputString: inputString)
print("\n \nurlsFoundInInputString are: \(urlsFoundInInputString)")
//2) Function to get the string components either side of a url from the inputString. Returns these components as an array of strings
func getStringComponentsSurroundingUrls(urlsFoundInInputString: [String]) -> [String] {
var stringComponentsSurroundingUrls: [String] = []
for (index, url) in urlsFoundInInputString.enumerated() {
let splitInputString = inputString.components(separatedBy: url)
//This code handles the case of an input string with 2 hyperlinks inside it (e.g. This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink www.apple.com. This is text after it.)
//In the 1st pass of the for loop, this will return splitInputString = ["This is 1 hyperlink ", ". This is a 2nd hyperlink www.apple.com. This is text after it."]
//Because the last element in the array contains either "www" or "http", we only append the contents of the first (prefix(1)) to stringComponentsSurroundingUrls (i.e "This is 1 hyperlink ")
//In the 2nd pass of the for loop, this will return splitInputString = ["This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink ", ". This is text after it."]
//Beacuse the last element in the array does not contain a hyperlink, we append both elements to stringComponentsSurroundingUrls
if splitInputString.last!.contains("www") || splitInputString.last!.contains("http") {
stringComponentsSurroundingUrls.append(contentsOf: inputString.components(separatedBy: url).prefix(1))
} else {
stringComponentsSurroundingUrls.append(contentsOf: inputString.components(separatedBy: url))
}
//At this point in the code, in the above example, stringComponentsSurroundingUrls = ["This is 1 hyperlink ",
// "This is 1 hyperlink www.google.co.uk. This is a 2nd hyperlink ",
// ". This is text after it."]
//We now iterate through this array of string, to complete another split. This time we separate out by any elements by urlsFoundInInputString[index-1]
//At the end of this for loop, stringComponentsSurroundingUrls = ["This is 1 hyperlink ",
// ". This is a 2nd hyperlink ",
// ". This is text after it."]
if index == urlsFoundInInputString.count - 1 {
for (index, stringComponent) in stringComponentsSurroundingUrls.enumerated() {
if index != 0 {
let stringComponentFurtherSeparated = stringComponent.components(separatedBy: urlsFoundInInputString[index-1])
stringComponentsSurroundingUrls.remove(at: index)
stringComponentsSurroundingUrls.insert(stringComponentFurtherSeparated.last!, at: index)
}
}
}
}
return stringComponentsSurroundingUrls
}
var stringComponentsSurroundingUrls: [String]
//If there no no urls found in the inputString, simply set stringComponentsSurroundingUrls equal to the input string as an array, else call the function to find the string comoponents surrounding the Urls found
if urlsFoundInInputString == [] {
stringComponentsSurroundingUrls = [inputString]
} else {
stringComponentsSurroundingUrls = getStringComponentsSurroundingUrls(urlsFoundInInputString: urlsFoundInInputString)
}
print("\n \nstringComponentsSurroundingUrls are: \(stringComponentsSurroundingUrls)")
//3)Function to markdown the urls found to follow a format of [placeholderText](hyperlink) such as [Google](https://google.com) so SwiftUI markdown can render it as a hyperlink
func markdown(urlsFoundInInputString: [String]) -> [String] {
var markdownUrlsArray: [String] = []
for url in urlsFoundInInputString {
let placeholderText = "[\(url)]"
var hyperlink: String
if url.hasPrefix("https://www.") {
hyperlink = "(\(url.replacingOccurrences(of: "https://www.", with: "https://")))"
} else if url.hasPrefix("www.") {
hyperlink = "(\(url.replacingOccurrences(of: "www.", with: "https://")))"
} else {
hyperlink = "(http://\(url))"
}
let markdownUrl = placeholderText + hyperlink
markdownUrlsArray.append(markdownUrl)
}
return markdownUrlsArray
}
let markdownUrls = markdown(urlsFoundInInputString: urlsFoundInInputString)
print("\n \nmarkdownUrls is: \(markdownUrls)")
//4) Function to combine stringComponentsSurroundingUrls and markdownUrls back together
func recombineStringComponentsAndMarkdownUrls(stringComponentsSurroundingUrls: [String], markdownUrls: [String]) -> [SplitMessageContentWithType] {
var text = SplitMessageContentWithType()
var text2 = SplitMessageContentWithType()
var splitMessageContentWithTypeAsArray: [SplitMessageContentWithType] = []
//Saves each string component and url as either .text or .url type so in the CustomTextWithHyperlinkAndUnderline() function, we can underline all .url types
for (index, stringComponents) in stringComponentsSurroundingUrls.enumerated() {
text.content = stringComponents
text.type = .text
splitMessageContentWithTypeAsArray.append(text)
if index <= (markdownUrls.count - 1) {
text2.content = markdownUrls[index]
text2.type = .url
splitMessageContentWithTypeAsArray.append(text2)
}
}
return splitMessageContentWithTypeAsArray
}
let recombineStringComponentsAndMarkdownUrls = recombineStringComponentsAndMarkdownUrls(stringComponentsSurroundingUrls: stringComponentsSurroundingUrls, markdownUrls: markdownUrls)
print("\n \nrecombineStringComponentsAndMarkdownUrls is: \(recombineStringComponentsAndMarkdownUrls)")
return recombineStringComponentsAndMarkdownUrls
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7099 次 |
| 最近记录: |