Disable Email Detection in Swiftui's Text

Disable email detection in SwiftUI's Text

You can use the verbatim: form of Text, which will skip the parsing step:

struct ContentView: View {
var body: some View {
Text(verbatim: "hello@gmail.com")
.padding()
}
}

Disable email detection in SwiftUI's Text

You can use the verbatim: form of Text, which will skip the parsing step:

struct ContentView: View {
var body: some View {
Text(verbatim: "hello@gmail.com")
.padding()
}
}

SwiftUI Text iOS15: Email or URL inside Text view render using accent color

You can use Text(verbatim:) to render the string as-is, and not automatically create a link from the email.

Text(verbatim: "Send a message to john@email.com to request support")
.foregroundColor(.blue)

Result:

Text is all blue

You can also set your own accent color, if you want.

Text("Send a message to john@email.com to request support")
.accentColor(.green)

Result:

Email is green, rest of text is black

How to make text typed in TextField undeletable?

The idea is the create UITextField class and use UIViewRepresentable to bind with SwiftUI view. By this, you can use all delegate methods and detect backspace. Also, using this you can prevent from cut and delete from tap action.

UndeletableTextField custom class

class UndeletableTextField: UITextField {

// This for prevent to cut and delete
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
if action == #selector(UIResponderStandardEditActions.delete(_:)) ||
action == #selector(UIResponderStandardEditActions.cut(_:)) {
return false
}
return super.canPerformAction(action, withSender: sender)
}
}

UIViewRepresentable view

struct UndeletableTextFieldUI: UIViewRepresentable {

@Binding var text: String
var placeholder: String

func makeUIView(context: Context) -> UndeletableTextField {
let textField = UndeletableTextField(frame: .zero)
textField.delegate = context.coordinator
textField.placeholder = placeholder
return textField
}

func updateUIView(_ uiView: UndeletableTextField, context: Context) {
uiView.text = text
}

func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}

class Coordinator: NSObject, UITextFieldDelegate {
var parent: UndeletableTextFieldUI

init(parent: UndeletableTextFieldUI) {
self.parent = parent
}

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Here we detect backspace and ignore it.
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
return false
}
}
return true
}
}
}

ContentView

struct ContentView: View {
@State private var text: String = ""
var body: some View {
UndeletableTextFieldUI(text: $text, placeholder: "Type here")
}
}

How to disable TextField with Toogle in SwiftUI?

The reason given by @Asperi is correct, but I would suggest other solution. When switching Toogle off, let's drop the focus on the TextField and only then disable it.

    @State var isToogleOn = false
@State var textFieldIsDisabled = false
@State var textFieldValue = ""

@FocusState private var focusField: Field?

var body: some View {
HStack {
TextField("Placeholde", text: $textFieldValue)
.focused($focusField, equals: .textField1)
.disabled(textFieldIsDisabled)
Toggle("Activate textField", isOn: $isToogleOn)
.onChange(of: isToogleOn) { newValue in
focusField = nil
textFieldIsDisabled = !newValue
}
}
}
}

How to disable TextField with Toogle in SwiftUI?

The reason given by @Asperi is correct, but I would suggest other solution. When switching Toogle off, let's drop the focus on the TextField and only then disable it.

    @State var isToogleOn = false
@State var textFieldIsDisabled = false
@State var textFieldValue = ""

@FocusState private var focusField: Field?

var body: some View {
HStack {
TextField("Placeholde", text: $textFieldValue)
.focused($focusField, equals: .textField1)
.disabled(textFieldIsDisabled)
Toggle("Activate textField", isOn: $isToogleOn)
.onChange(of: isToogleOn) { newValue in
focusField = nil
textFieldIsDisabled = !newValue
}
}
}
}

SwiftUI Text - how can I create a hyperlink and underline a weblink in a string

This was the final solution I used. Should work for a variety of string inputs.

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 quot;, .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

}


Related Topics



Leave a reply



Submit