Make some text in UILabel blue and clickable - ios

I need to make "Terms of Use" in the string below blue and have it respond to an click. I don't want to use a button so how can I do this in a UILabel?
String: By tapping Next and continuing you agree to the Terms of Use
Code I tried but failed just got text color change:
var myMutableString = NSMutableAttributedString()
myMutableString = NSMutableAttributedString(string: self.termsLabel.text! as String, attributes: [NSFontAttributeName:UIFont(name: self.termsLabel.font.fontName, size: self.termsLabel.font.pointSize)!])
myMutableString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range: NSRange(location:self.termsLabel.text!.characters.count - 12,length:12))
self.termsLabel.attributedText = myMutableString

Don't use a UILabel. Use a UITextField or UITextView, and install attributed text into it, including a link. Then set up the delegate methods to detect & respond to links. You need to implement the UITextViewDelegate method
func textView(UITextView,
shouldInteractWith: URL,
in: NSRange,
interaction: UITextItemInteraction)
One of the easiest ways to configure your link is to load the contents of an RTF file into the field.
I have a demo project on GitHub called DatesInSwift that creates clickable links that trigger a custom URL that invokes the URL in the app.
That project uses an extension to UITextView that has adds #IBInspectable property RTF_Filename to UITextView fields. All you have to do is to set the RTF_Filename property of your text view to the filename of the RTF file that you need to load.
It looks like my project was written for Swift 2, and uses the old version of the UITextViewDelegate method, which was called
func textView(_ textView: UITextView,
shouldInteractWithURL URL: Foundation.URL,
inRange characterRange: NSRange) -> Bool

I came to the conclusion that i couldn't get exactly what I wanted so I threw the text in a button and added this code
let mainText = "By tapping Next and continuing you agree to the Terms Of Use"
let attributeText = "Terms Of Use"
let range = (mainText as NSString).range(of: attributeText)
let attributedString = NSMutableAttributedString(string:mainText)
attributedString.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range: range)
self.termsLabel.attributedText = attributedString
let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.goToTOSView))
tapGesture.numberOfTapsRequired = 1
self.termsLabel.isUserInteractionEnabled = true
self.termsLabel.addGestureRecognizer(tapGesture)

Related

UITextView rich text editing

I need to implement a text editor using UITextView that supports:
Bold/Italic/Underline
Color,Font,font size changes
Paragraph alignment
List format (bullets, numbers, etc.)
Custom selection of text anywhere in the text view and change the properties
So far I have managed to do it without NSTextStorage but it seems I am hitting limits. For instance, to change font, I use UIFontPickerViewController and change the font as follows:
func fontPickerViewControllerDidPickFont(_ viewController: UIFontPickerViewController) {
if let selectedFontDesc = viewController.selectedFontDescriptor {
let font = UIFont(descriptor: selectedFontDesc, size: selectedFontDesc.pointSize)
self.selectedFont = font
self.textView.typingAttributes = [NSAttributedString.Key.foregroundColor: self.selectedColor ?? UIColor.white, NSAttributedString.Key.font: self.selectedFont ?? UIFont.preferredFont(forTextStyle: .body, compatibleWith: nil)]
if let range = self.textView.selectedTextRange, let selectedFont = selectedFont {
let attributedText = NSMutableAttributedString(attributedString: self.textView.attributedText)
let location = textView.offset(from: textView.beginningOfDocument, to: range.start)
let length = textView.offset(from: range.start, to: range.end)
let nsRange = NSRange(location: location, length: length)
attributedText.setAttributes([NSAttributedString.Key.font : selectedFont], range: nsRange)
self.textView.attributedText = attributedText
}
}
}
This works but the problem is it resets the color of the selected text and other properties. I need to understand a way in which the existing attributed of the text under selection are not disturbed. I suspect the way to do is with using NSTextStorage but I can't find anything good on internet that explains the right use of NSTextStorage to achieve this.
The problem is this call:
attributedText.setAttributes...
This, as you have observed, makes the attribute you provide (here, the font) the only attribute of this range. Instead, you want to add your font attribute to the existing attributes:
https://developer.apple.com/documentation/foundation/nsmutableattributedstring/1414304-addattributes

How to embed a custom button within a label in swift?

I've created a custom info button that I want to put inside a regular UILabel.
The idea is to have the screen say "Tap the (BUTTON HERE) for more information". Is there a way to do this without creating two UILabels? And if creating 2 labels is the only way, how can I put everything on one line?
I tried to do (button) inside the label.text but that shows the button's properties instead of placing the button. I also tried label.addSubview(button) which works but adds the button in the wrong place.
The best way to do this is using a UITextView with an NSAttributedString, where one of the attributes is your link.
let textView = UITextView()
textView.delegate = self
// These allow the link to be tapped
textView.isEditable = false
textView.isScrollEnabled = false
// Removes padding that UITextView uses, making it look more like a UILabel
textView.textContainer.lineFragmentPadding = 0.0
textView.textContainerInset = .zero
Then for the NSAttributedString
let text = "Tap HERE for more information"
let linkText = "HERE"
// Get range for tappable section
let linkRange = (text as NSString).range(of: linkText)
// Styling
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.black
]
// Actual Link!
let linkTextAttributes: [NSAttributedString.Key: Any] = [
.underlineStyle: NSUnderlineStyle.single.rawValue,
.link: "https://www.example.com" //The link you want to link to
]
let attributedString = NSMutableAttributedString(string: text, attributes: attributes)
attributedString.addAttributes(linkTextAttributes, range: linkRange)
Then use these UITextView delegate functions
// Removes a lot of the actions when user selects text
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
// Handle the user tapping the link however you like here
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
viewModel.urlTapped(URL)
return false
}

How to set color for attributed string of UITextField programmatically?

I'm working on a iOS app with Swift. And I have to implement multiple colors for text in UITextField. So far I know how to set color for different parts of UITextField text and how to concatenate them.
This is the example of that:
let attributedString = NSMutableAttributedString(string: string, attributes: [:])
attributedString.addAttribute(NSForegroundColorAttributeName,
value: color,
range: NSRange(location: 0, length: string.characters.count))
But when I press delete button and erase some of the text, and when I start wright again, the new text has the color of the last deleted text. I want default color for every new character, regardless which was the last color (color of text when deleting) for text in UITextField. Can I set color or some attribute of text (new text) in this function?
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
So, when new character has been written it will be in my desired color, black for instance. Thanks for your answers.

If i wanted to change the color of a specific word entered in textview, How would i do that?

From what i've read i would need to use rangeOfString to search a textview entry but am unsure about how to go about that. Is it possible to change the color of a text entered in textview in real time, for example if someone wrote "blue," could i change the word to blue the moment they typed it. If so how would i go about that? I'm very new to coding and even newer to swift.
You will have to use attributed text for your text view and then use the textView(textView: UITextView, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool method, which will be triggered whenever the text in the text view's text changes. Apply your own logic in there as to what range the colored text will fall into and how that will happen...
Make sure your controller conforms to the UITextViewDelegate protocol and make the textView's delegate your controller.
Demonstration:
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.delegate = self // important! Otherwise the textView will not know where to call the delegate functions!
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// first make sure that the text field is the one we want to actually change
if textView == self.textView{
let nsString = textView.text as NSString // we explicitly cast the Swift string to NSString so that we can use rangeOfString for example
let stringLength = textView.text.characters.count
// Arbitrarily check if the string in the text field is not empty
// Apply your own logic for when to update the string
if stringLength > 0{
let text = NSMutableAttributedString(string: textView.text)
// Currently the range is assumed to be the whole text (the range covers the whole string)
// You'll have to apply your own logic here
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, stringLength))
textView.attributedText = text
}
}
return true
}
}
For example, instead of using the above to color the whole text
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, stringLength))
Color the first occurence of "hello" in red:
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: nsString.rangeOfString("hello"))
Note that I explicitly cast the textView's text to NSString so that we can use the range functions such as (rangeOfString())
Changes were made to swift in which count no longer seems to work with String. I made a slight change to the answer given by the_critic (https://stackoverflow.com/users/1066899/the-critic). Thank you to all who helped
class ViewController: UIViewController, UITextViewDelegate {
#IBOutlet weak var textView: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
self.textView.delegate = self // important! Otherwise the textView will not know where to call the delegate functions!
}
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
// first make sure that the text field is the one we want to actually change
if textView == self.textView{
let nsString = textView.text as NSString // we explicitly cast the Swift string to NSString so that we can use rangeOfString for example
let stringLength = textView.text.characters.count
// Arbitrarily check if the string in the text field is not
empty
// Apply your own logic for when to update the string
if stringLength > 0{
let text = NSMutableAttributedString(string: textView.text)
// Currently the range is assumed to be the whole text (the range covers the whole string)
// You'll have to apply your own logic here
text.addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSMakeRange(0, stringLength))
textView.attributedText = text
}
}
return true
}
}

How to remember text attributes in UITextView when the user starts typing

I'm using a UITextView and I'm trying to have the text displayed using the attributedText property as the user types.
Here's my current code:
textView.attributedText = NSMutableAttributedString(
string: "",
attributes: [
NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Regular", size: 12.5)!,
NSForegroundColorAttributeName: UIColor.colorFromCode(0x262626),
NSKernAttributeName: 0.5,
NSParagraphStyleAttributeName: paragraphStyle
]
)
The problem is that if you supply an empty string, when the user starts typing, the text isn't being formatted with the attributedText properties.
However, I noticed if I supply a string, as the user begins to append that string, the text is formatted with the attributedText properties.
The only way I can think to accomplish what I need would be to override this function and set the text to attributedText everytime a user enters a key:
func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool
Is there no other better way to do this?
Instead of setting an empty attributed string you need to use the typingAttributes property.
textView.typingAttributes = [
NSFontAttributeName: UIFont(name: "AvenirNextLTPro-Regular", size: 12.5)!,
NSForegroundColorAttributeName: UIColor.colorFromCode(0x262626),
NSKernAttributeName: 0.5,
NSParagraphStyleAttributeName: paragraphStyle
]
See also the official documentation.
The attributes to apply to new text being entered by the user.

Resources