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:
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:
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
How to Integrate Mapbox Sdk with Swiftui
Use of or Operator on Cloudkit Predicate
How to Execute Multiplications And/Or Divisions in the Right Order
Can the Byte Order of Double Be Safely Reversed
Hiding Dividers in Nssplitview
Swift 3 - How to Insert Tableviewcells from Another View
Convert from Utc to Local Timezone Give Wrong Result
Unexpectedly Found Nil While Unwrapping an Optional Value Parsing JSON Swift
Differencebetween Sequencetype and Collectiontype in Swift
Swift: How to Get Information for an Application Which Is Not Running
Swiftui Mysterious Spacing Between Large Text and Textfield in VStack
Store Data in Custom Class Array in Core Data
Downloading Firebase Storage Files Device Issue
Is There a Neat Way to Represent a Fraction as an Attributed String
Checkboxes in Uitableview State Persistence
Where to Implement Nsvaluetransformer for Core Data in Swift