I have a signup page with privacy and term&condition. I am using textview controller for show content when I was clicked any of them show another view controller, I tried this code but it's not working,
let signUpTermsAndPrivacyString = NSMutableAttributedString(string: "I have read and understood PayGyft Terms of Usage and Privacy Policy",attributes: [NSAttributedStringKey.font: UIFont(name: "Helvetica", size: 15.0)!,NSAttributedStringKey(rawValue: NSAttributedStringKey.foregroundColor.rawValue): UIColor.darkGray])
let termsString = signUpTermsAndPrivacyString.mutableString.range(of: "Terms of Usage")
print("termsSTring",termsString)
signUpTermsAndPrivacyString.addAttribute(.link, value: "http://gregoryadunbar.com", range: termsString)
let privacyString = signUpTermsAndPrivacyString.mutableString.range(of: "Privacy Policy")
signUpTermsAndPrivacyString.addAttribute(.link, value:"http://gregoryadunbar.com", range: privacyString)
termsPrivacyPolicyTextView.attributedText = signUpTermsAndPrivacyString
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
if (URL.absoluteString == termsURLString) {
print("termsURLString")
} else if (URL.absoluteString == privacyURLString) {
print("privacyURLString")
}
return false
}
You need to add myTextView.linkTextAttributes
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attributes = [NSAttributedStringKey.foregroundColor : UIColor.init(rgb: 0x646464),
NSAttributedStringKey.font : AppFont.getFont(fontType: .regular, ofSize: 16),
NSAttributedStringKey.paragraphStyle : paragraphStyle]
let attributedText = NSMutableAttributedString(string: descriptonText,
attributes: attributes)
if let range = attributedText.string.range(of: "terms & conditions") {
let nsRange = NSRange(range, in: attributedText.string)
attributedText.addAttributes([NSAttributedStringKey.link : "link://T&C"], range: nsRange)
}
let linkColor = UIColor.init(red: 47, green: 117, blue: 83)
let linkAttrs: [String: Any] = [NSAttributedStringKey.foregroundColor.rawValue : linkColor,
NSAttributedStringKey.underlineColor.rawValue : linkColor,
NSAttributedStringKey.underlineStyle.rawValue : NSUnderlineStyle.styleSingle.rawValue]
descriptionTextView.linkTextAttributes = linkAttrs
let textView = UITextView(frame: descriptionTextView.bounds)
textView.attributedText = attributedText
textView.layoutIfNeeded()
textView.sizeToFit()
let size = textView.sizeThatFits(CGSize(width: textView.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
descriptionTextViewHeight.constant = size.height
descriptionTextView.attributedText = attributedText
And in delegate:
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
return false
}
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return false
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
debugPrint(URL.absoluteString)
if URL.absoluteString.contains("link://") {
// my func call
dismissAnimated()
}
return false
}
Also set isEditable to false and isSelectable to true. Subclass textView and return false in canPerformAction. In awakeFromNib set textDragInteraction?.isEnabled = false
Related
I have a UITextView that has some text, and then should have a clickable string at the end of the paragraph, but I'm not sure how to approach this. I wanted to use attributed strings, but I cannot add a target to the attributed string to make it clickable. How can I accomplish this?
You can use UITextViewDelegate to detect iuser interation.
#IBOutlet weak var mapTextView: UITextView!
func setupTextView() {
let mapAttributedText = NSMutableAttributedString(string: "Click here to get directions")
mapAttributedText.addAttribute(NSAttributedString.Key.link, value: "customValue", range: mapAttributedText.mutableString.range(of: "Click here"))
let linkArr = [NSAttributedString.Key.foregroundColor: UIColor.blue,NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue,NSAttributedString.Key.underlineColor: UIColor.blue] as [NSAttributedString.Key : Any]
mapTextView.linkTextAttributes = linkArr
mapTextView.attributedText = mapAttributedText
mapTextView.delegate = self
mapTextView.isEditable = false
}
extension YourVCName: UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
if URL.absoluteString == "customValue" {
// Do something
}
return false
}
}
I have a pop-up window, that shows terms of service & privacy policy for users, how to disable text selection but keep links tappable. screenshot
If I set:
SOLVED: By adding textViewDidChangeSelection method in UIViewDelegate and setting
textView.isSelectable = false
textView.isUserInteractionEnabled = true
textView.isSelectable = true
Links become uninteractable.
How do I keep the link tappable and text not selectable?
My whole class:
// HyperLinkTextView.swift
import SwiftUI
struct Hyperlink {
var word: String
var url: NSURL
}
struct HyperLinkTextView: UIViewRepresentable {
private var text: String
private var links: [Hyperlink]
let textView = UITextView()
init(text: String, links: [Hyperlink]) {
self.text = text
self.links = links
}
func makeUIView(context: Self.Context) -> UITextView {
let attributedString = NSMutableAttributedString(string: text)
links.forEach { hyperlink in
let linkAttributes = [NSAttributedString.Key.link: hyperlink.url]
var nsRange = NSMakeRange(0, 0)
if let range = text.range(of: hyperlink.word) {
nsRange = NSRange(range, in: text)
}
attributedString.setAttributes(linkAttributes, range: nsRange)
attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSNumber(value: 1), range: nsRange)
}
textView.isEditable = false
textView.delegate = context.coordinator
textView.attributedText = attributedString
textView.linkTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor(Theme.colorClickables)]
textView.isUserInteractionEnabled = true
textView.isSelectable = true
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
uiView.font = UIFont(name: "ArialMT", size: 18)
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
public class Coordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate {
weak var textView: UITextView?
public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction, replacementText text: String) -> Bool {
return true
}
func textViewDidChangeSelection(_ textView: UITextView) {
if textView.selectedTextRange != nil {
textView.delegate = nil
textView.selectedTextRange = nil
textView.delegate = self
}
}
}
}
Add this UITextViewDelegate textViewDidChangeSelection and comment out isEditable and isSelectable:
func textViewDidChangeSelection(_ textView: UITextView) {
if textView.selectedTextRange != nil {
textView.delegate = nil
textView.selectedTextRange = nil
textView.delegate = self
}
}
I have an attributed string. I'd like to add custom actions for the highlighted attributed text. Which is dataModel.user & dataModel.object How would I go about doing this?
My Attributed Text is;
var title: NSAttributedString {
let highlighted: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16, weight: .semibold),
NSAttributedString.Key.foregroundColor: UIColor.label]
let regular: [NSAttributedString.Key: Any] = [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 16, weight: .regular),
NSAttributedString.Key.foregroundColor: UIColor.gray]
let title = NSMutableAttributedString(string: dataModel.user, attributes: highlighted)
let added = NSMutableAttributedString(string: " added ", attributes: regular)
let object = NSMutableAttributedString(string: dataModel.object, attributes: highlighted)
title.append(added)
title.append(object)
return title
}
You can simply set your view controller as the delegate of your UITextView, add link attributes to the user and object strings with a path/name using an url and switch that url last path component inside UITextView shouldInteractWith method.
struct DataModel {
let user: String
let object: String
}
import UIKit
class ViewController: UIViewController, UITextViewDelegate {
var dataModel: DataModel!
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
textView.delegate = self
dataModel = .init(user: "Steve", object: "Jobs")
textView.attributedText = {
let title = NSMutableAttributedString(string: dataModel.user, attributes: [
.font: UIFont.systemFont(ofSize: 16, weight: .semibold),
.foregroundColor: UIColor.label,
.link: URL(fileURLWithPath: "user")])
let added = NSMutableAttributedString(string: " added ", attributes: [
.font: UIFont.systemFont(ofSize: 16, weight: .regular),
.foregroundColor: UIColor.gray])
let object = NSMutableAttributedString(string: dataModel.object, attributes: [
.font: UIFont.systemFont(ofSize: 16, weight: .semibold),
.foregroundColor: UIColor.label,
.link: URL(fileURLWithPath: "object")])
title.append(added)
title.append(object)
return title
}()
}
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
switch URL.lastPathComponent {
case "user": print("user action")
case "object": print("object action")
default: break
}
return true
}
}
I have this Custom UITextView that uses "ShouldInteractWith" method:
class StudyText: UITextView, UITextViewDelegate {
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
print(URL)
return false
}
}
struct ClickableText: UIViewRepresentable {
#Binding var text: NSMutableAttributedString
func makeUIView(context: Context) -> StudyText {
let view = StudyText()
view.dataDetectorTypes = .all
view.isEditable = false
view.isSelectable = true
view.delegate = view
view.isUserInteractionEnabled = true
return view
}
func updateUIView(_ uiView: StudyText, context: Context) {
uiView.attributedText = text
}
}
I have this extension to set a link to the attributed text:
extension NSMutableAttributedString {
func apply(link: String, subString: String) {
if let range = self.string.range(of: subString) {
self.apply(link: link, onRange: NSRange(range, in: self.string))
}
}
private func apply(link: String, onRange: NSRange) {
self.addAttributes([NSAttributedString.Key.link: link], range: onRange)
}
}
And I created this layout:
struct contentView: View {
#State text: NSMutableAttributedString = NSMutableAttributedString(string: "")
var body: some View {
VStack {
ClickableText(text: self.$text)
}
.onAppear{
let myText = "Click Me!"
let attributedString = NSMutableAttributedString(string: myText)
attributedString.apply(link: "Soeme random link", subString: myText)
self.text = attributedString
}
}
}
When I click on the text view it doesn't print anything to the console and sometimes it crashes.
How can I fix this?
It must be provided valid URL, like
let attributedString = NSMutableAttributedString(string: myText)
attributedString.apply(link: "https://www.google.com", subString: myText)
shouldInteractWith url textview delegate not called in ios9 but i have implemented ios9 delegate method also. Code is below. If someone knows whats the issue fix then please let me know. thanks in advance for any help
import UIKit
class UrNestTermsView: UIView {
// Outlets
#IBOutlet weak var contentView: UIView!
#IBOutlet weak var termsTextView: UITextView!
#IBOutlet weak var termsUrNestCheckBox: UrNestCheckBox!
#IBOutlet weak var subscribeUrNestCheckBox: UrNestCheckBox!
#IBOutlet weak var subscribeTextView: UITextView!
fileprivate let fontOfTerms = UIFont.systemFont(with: 10)
fileprivate let labelTextColor = UIColor(colorLiteralRed: 102/255, green: 110/255, blue: 111/255, alpha: 1)
override func awakeFromNib() {
super.awakeFromNib()
self.setUp()
}
}
extension UrNestTermsView: UITextViewDelegate {
func setUp() {
self.subscribeTextView.textColor = labelTextColor
self.subscribeTextView.font = fontOfTerms
self.setUpTextView()
}
func setUpTextView() {
// You must set the formatting of the link manually
let linkAttributeTermsOfService = [
NSLinkAttributeName: NSURL(string: "https://www.apple.com")!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSForegroundColorAttributeName: labelTextColor
] as [String : Any]
let linkAttributePolicy = [
NSLinkAttributeName: NSURL(string: "https://www.google.com")!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSForegroundColorAttributeName: labelTextColor
] as [String : Any]
let linkAttributePaymentsTermsOfService = [
NSLinkAttributeName: NSURL(string: "https://www.amazon.com")!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSForegroundColorAttributeName: labelTextColor
] as [String : Any]
let linkAttributeGuestRefundPolicy = [
NSLinkAttributeName: NSURL(string: "https://www.yahoo.com")!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSForegroundColorAttributeName: labelTextColor
] as [String : Any]
let linkAttributeHostGuaranteeTerms = [
NSLinkAttributeName: NSURL(string: "https://www.assembla.com")!,
NSUnderlineStyleAttributeName: NSUnderlineStyle.styleSingle.rawValue,
NSForegroundColorAttributeName: labelTextColor
] as [String : Any]
let attributedString = NSMutableAttributedString(string: kTermsAndPolicy)
// Set the 'click here' substring to be the link
attributedString.setAttributes(linkAttributeTermsOfService, range: NSMakeRange(33, 16))
attributedString.setAttributes(linkAttributePolicy, range: NSMakeRange(51, 6))
attributedString.setAttributes(linkAttributePaymentsTermsOfService, range: NSMakeRange(59, 25))
attributedString.setAttributes(linkAttributeGuestRefundPolicy, range: NSMakeRange(102, 19))
attributedString.setAttributes(linkAttributeHostGuaranteeTerms, range: NSMakeRange(127, 20))
attributedString.addAttribute(NSFontAttributeName, value: fontOfTerms, range: NSMakeRange(0, attributedString.length-1))
attributedString.addAttribute(NSForegroundColorAttributeName, value: labelTextColor, range: NSMakeRange(0, attributedString.length-1))
self.termsTextView.delegate = self
self.termsTextView.attributedText = attributedString
let attributedStringOfSubscribe = NSMutableAttributedString(string: kSubscribe)
attributedStringOfSubscribe.addAttribute(NSFontAttributeName, value: fontOfTerms, range: NSMakeRange(0, attributedStringOfSubscribe.length))
attributedStringOfSubscribe.addAttribute(NSForegroundColorAttributeName, value: labelTextColor, range: NSMakeRange(0, attributedStringOfSubscribe.length))
self.subscribeTextView.delegate = self
self.subscribeTextView.attributedText = attributedStringOfSubscribe
}
//For iOS 7...9
#available(iOS, deprecated: 10.0)
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool {
return true
}
#available(iOS 10.0, *)
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return true
}
}
you must check Selectable in storyboard or do it in code :
textView.isSelectable = true
try this:
#available(iOS, deprecated: 10.0)
func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange) -> Bool {
return true
}
//For iOS 10
#available(iOS 10.0, *)
func textView(_ textView: UITextView, shouldInteractWith url: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return true
}