Swiftui Tappable Subtext

SwiftUI tappable subtext

Update for iOS 15 and higher:
There is a new Markdown formatting support for Text, such as:

Text("Some text [clickable subtext](some url) *italic ending* ")

you may check WWDC session with a timecode for details

The old answer for iOS 13 and 14:

Unfortunately there is nothing that resembles NSAttributedString in SwiftUI. And you have only a few options. In this answer you can see how to use UIViewRepresentable for creating an old-school UILabel with click event, for example. But now the only SwiftUI way is to use HStack:

struct TappablePieceOfText: View {

var body: some View {

HStack(spacing: 0) {
Text("Go to ")
.foregroundColor(.gray)

Text("stack overflow")
.foregroundColor(.blue)
.underline()
.onTapGesture {
let url = URL.init(string: "https://stackoverflow.com/")
guard let stackOverflowURL = url, UIApplication.shared.canOpenURL(stackOverflowURL) else { return }
UIApplication.shared.open(stackOverflowURL)
}

Text(" and enjoy")
.foregroundColor(.gray)
}


}
}

UPDATE
Added solution with UITextView and UIViewRepresentable. I combined everything from added links and the result is quite good, I think:

import SwiftUI
import UIKit

struct TappablePieceOfText: View {

var body: some View {
TextLabelWithHyperlink()
.frame(width: 300, height: 110)
}

}

struct TextLabelWithHyperlink: UIViewRepresentable {

func makeUIView(context: Context) -> UITextView {

let standartTextAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 20),
NSAttributedString.Key.foregroundColor: UIColor.gray
]

let attributedText = NSMutableAttributedString(string: "You can go to ")
attributedText.addAttributes(standartTextAttributes, range: attributedText.range) // check extention

let hyperlinkTextAttributes: [NSAttributedString.Key : Any] = [
NSAttributedString.Key.font: UIFont.systemFont(ofSize: 20),
NSAttributedString.Key.foregroundColor: UIColor.blue,
NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue,
NSAttributedString.Key.link: "https://stackoverflow.com"
]

let textWithHyperlink = NSMutableAttributedString(string: "stack overflow site")
textWithHyperlink.addAttributes(hyperlinkTextAttributes, range: textWithHyperlink.range)
attributedText.append(textWithHyperlink)

let endOfAttrString = NSMutableAttributedString(string: " end enjoy it using old-school UITextView and UIViewRepresentable")
endOfAttrString.addAttributes(standartTextAttributes, range: endOfAttrString.range)
attributedText.append(endOfAttrString)

let textView = UITextView()
textView.attributedText = attributedText

textView.isEditable = false
textView.textAlignment = .center
textView.isSelectable = true

return textView
}

func updateUIView(_ uiView: UITextView, context: Context) {}

}

result of HStack and Text:
HStack and Text

result of UIViewRepresentable and UITextView:

Sample Image

UPDATE 2:
here is a NSMutableAttributedString little extension:

extension NSMutableAttributedString {

var range: NSRange {
NSRange(location: 0, length: self.length)
}

}

How to create tappable url/phone number in SwiftUI

Using iOS 14 / Xcode 12.0 beta 5

Use new link feature in SwiftUI for phone and email links.

    // Link that will open Safari on iOS devices
Link("Apple", destination: URL(string: "https://www.apple.com")!)

// Clickable telphone number
Link("(800)555-1212", destination: URL(string: "tel:8005551212")!)

// Clickable Email Address
Link("apple@me.com", destination: URL(string: "mailto:apple@me.com")!)

Creating a big paragraph with clickable Text in SwiftUI

You are pushing this version of SwiftUI beyond its current capabilities!

Something like this would more easily be done using the advanced text handling in UIKit, or by thinking outside the box and converting the text to something Like HTML.

If you MUST use SwiftUI, your best bet would probably be to layout the formatted text first onto a tappable paragraph/block, and then use gesture recognition at the block level to detect where in the block the tap took place - indirectly determining if the tap position coincided with the “tappable” text.

Update #1:

Example: To use a UITextView (which supports attributed text), you could use the UIViewRepresentable protocol to wrap the UIKit view and make it accessible from within SwiftUI. e.g. Using Paul Hudson's UIViewRepresentable example for the code...

struct TextView: UIViewRepresentable {
@Binding var text: String

func makeUIView(context: Context) -> UITextView {
return UITextView()
}

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

The TextView can then be used directly within SwiftUI.

Now, while Textview gives you formatting, it does not give you the clickability you need without a lot of extra work, but a WKWebView used to render an HTML version of your text would allow you to convert the clickable text into HTML links that could be handled internal to your new SwiftUI view.

Note: The reason I say that you are pushing SwiftUI to its limits is that the current version of SwiftUI hides a lot of the configurability that is exposed in UIKit and forces you to do cartwheels to get to a solution that is often already present in UIKit.

Update #2:

Here's a clickable version that uses UITextField and a NSAttributedString:

class MyTextView: UITextView, UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
print(URL)

return false
}
}

struct SwiftUIView: UIViewRepresentable {
@Binding var text: NSAttributedString

func makeUIView(context: Context) -> MyTextView {
let view = MyTextView()

view.dataDetectorTypes = .link
view.isEditable = false
view.isSelectable = true
view.delegate = view

return view
}

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

All you need to do now is convert the downloaded text into a suitable attributed string format and you have attributed formatting and clickability

SwiftUI handler to capture tapped link in markdown Text view

you could try something like this example code. It loops over your baseText, creates the appropriate links, and when the link is tapped/actioned you can put some more code to deal with it.

struct ContentView: View {
let baseText = "apple banana pear orange lemon"
let baseUrl = "https://api.github.com/search/repositories?q="

var body: some View {
let clickableText = baseText.split(separator: " ").map{ "[\($0)](\(baseUrl)\($0))" }
ForEach(clickableText, id: \.self) { txt in
let attributedString = try! AttributedString(markdown: txt)
Text(attributedString)
.environment(\.openURL, OpenURLAction { url in
print("---> link actioned: \(txt.split(separator: "=").last)" )
return .systemAction
})
}
}
}

How to Highlight and Clickable if Text is URL SwiftUI

You need to create custom UIViewRepresentable for TextView.

check below code this might help you.

struct TextView: UIViewRepresentable {

@Binding var text: String
@Binding var textStyle: UIFont.TextStyle

func makeUIView(context: Context) -> UITextView {
let textView = UITextView()

textView.delegate = context.coordinator
textView.font = UIFont.preferredFont(forTextStyle: textStyle)
textView.autocapitalizationType = .sentences
textView.isSelectable = true
textView.isUserInteractionEnabled = true
textView.isEditable = false
textView.dataDetectorTypes = .link

return textView
}

func updateUIView(_ uiView: UITextView, context: Context) {
uiView.text = text
uiView.font = UIFont.preferredFont(forTextStyle: textStyle)
}

func makeCoordinator() -> Coordinator {
Coordinator($text)
}

class Coordinator: NSObject, UITextViewDelegate {
var text: Binding<String>

init(_ text: Binding<String>) {
self.text = text
}

func textViewDidChange(_ textView: UITextView) {
self.text.wrappedValue = textView.text
}
}
}

In your "Receiver User Code:-" same for "Sender User Code"

struct SenderReciverUI1: View {
@State private var message = "Hello, www.google.com. this is just testing for hyperlinks, check this out our website https://www.apple.in thank you."
@State private var textStyle = UIFont.TextStyle.body

var body: some View {
Group {
HStack(alignment: .bottom){
VStack(alignment: .leading,spacing:5) {
HStack(alignment: .bottom) {
TextView(text: $message, textStyle: $textStyle)
.foregroundColor(.white)
.padding(10)
.cornerRadius(10.0)
}
}
Spacer()
}.padding(.vertical,5)
.padding()
}
}
}

let me know if you need anything.

SwiftUI concatenate multiline tappable Text

thanks to @Asperi

Text("[Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec metus urna, mollis sit amet tincidunt a, elementum in tellus. Donec placerat pharetra scelerisque](action1) [Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ultrices elementum orci, gravida lacinia dui congue quis. Vivamus at augue velit.](action2)")
.environment(\.openURL, OpenURLAction { url in
print("\(url)")
return .handled
})

It works since iOS 14



Related Topics



Leave a reply



Submit