I'm using attributed text (NSMutableAttributedString, to be exact) to display text that can be either italicized, bold, or have a hyperlink (sometimes combinations of these come up as well).
When I did this with UILabel it displayed exactly as I wanted it, but the links weren't functional. I switched over to UITextView and the links are fully functional, but the italicized and bold fonts aren't working.
We're pulling in the data from xml files, so I can't just specify certain words to set, but I don't think I would need to since this is working with labels.
"but the italicized and bold fonts aren't working"
Not sure what exactly is not working but here is a snippet of code that does change font traits in the attributed text:
#IBOutlet weak var content: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let fontDescriptor = UIFontDescriptor.preferredFontDescriptorWithTextStyle(UIFontTextStyleBody)
let existingTraitsWithNewTrait = fontDescriptor.symbolicTraits.rawValue | UIFontDescriptorSymbolicTraits.TraitBold.rawValue | UIFontDescriptorSymbolicTraits.TraitItalic.rawValue
let changedFontDescriptor: UIFontDescriptor = fontDescriptor.fontDescriptorWithSymbolicTraits(UIFontDescriptorSymbolicTraits(rawValue: existingTraitsWithNewTrait))!
let updatedFont = UIFont(descriptor: changedFontDescriptor, size:0.0)
let attributes = [NSFontAttributeName: updatedFont]
let attributedString: NSAttributedString? = NSAttributedString(string: "Hello World!", attributes: attributes)
content.attributedText = attributedString!
}
Related
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
I'm working on a barebones text editor, and I've run into an issue. I have two buttons at the top of the app: Bold and Italic. While I have already figured out how to make these buttons alter the text being entered into the textview, they change everything written in the view, including things already written. So hitting "Italic" will italicize everything in the view. I'm wanting more along the lines of "I'm hitting italicize -- oh cool now I'm writing in italics. Now I'm hitting it again-- and it's normal again."
I know this issue is stemming from the buttons changing the font the whole view is using, I just can't figure out the correct way to be doing this.
Here's my code so far:
#IBAction func italicizeHit(_ sender: Any) {
if isItalics == false {
textView.font = UIFont.italicSystemFont(ofSize: 15)}
else{
isItalics == false;
textView.font = UIFont.systemFont(ofSize: 15)
}
}
I also can't quite figure out what to set the textView.font to in order to return it to its normal state, but that's a more secondary problem. I'm mostly interested in correctly toggling italicize.
The issue here is that textView.font sets all of the textView's text to that property.
In order to achieve multiple styles, you're going to need to use a NSAttributedString (which can store bold, italic, and regular text all in the same string) rather than just a plain String.
The good news, a textView can easily take a NSAttributedString instead of a regular String. In order to change properties, use the typingAttributes property of the textView. This will change the style of any new text typed and not the entire textView. Here's an example:
class ViewController: UIViewController {
let textView: UITextView // initialize textView either via storyboard or code
let attributesBold = [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16, weight: .bold)]
let attributesNormal = [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16, weight: .regular)]
override func viewDidLoad() {
textView.attributedText = NSAttributedString(string: "")
textView.typingAttributes = attributesNormal
}
#IBAction func boldTapped(_ sender: Any) {
textView.typingAttributes = attributesBold
}
}
I want to change the label.text on my story board. The only way I know how to do it now is by clicking the label and on attribute fields change it, or changing it is when a button pressed.
But I want to change the .text on the story board. Sorry for the confusion, see the picture to make it more understandable.
Sounds like you just need to add the change code to your viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
titlebar.text = "New Title"
}
Answer has been updated for Swift 4.2
General form of setting and getting attributed string is given below
// create attributed string
let myString = "Swift Attributed String"
let myAttribute = [ NSAttributedString.Key.foregroundColor: UIColor.blue ]
let myAttrString = NSAttributedString(string: myString, attributes: myAttribute)
// set attributed text on a UILabel
myLabel.attributedText = myAttrString
I'm using iOS 11 and Swift 4.
I am trying to programmatically generate a link inside a UITextView.
All the attributes work (i.e. color, size, range etc.) - but unfortunately, the link does not work. Can anybody tell me why?
Here is my code:
#IBOutlet weak var textView: UITextView!
// Setting the attributes
let linkAttributes = [
NSAttributedStringKey.link: URL(string: "https://www.apple.com")!,
NSAttributedStringKey.font: UIFont(name: "Helvetica", size: 18.0)!,
NSAttributedStringKey.foregroundColor: UIColor.blue
] as [NSAttributedStringKey : Any]
let attributedString = NSMutableAttributedString(string: "Just click here to do stuff...")
// Set the 'click here' substring to be the link
attributedString.setAttributes(linkAttributes, range: NSMakeRange(5, 10))
self.textView.delegate = self
self.textView.attributedText = attributedString
Again, the link seems correct, but clicking it does not work.
Here is the screenshot:
You should enable isSelectable and disable isEditable for your text view.
textView.isSelectable = true
textView.isEditable = false
You can also set up these behaviors inside Interface Builder in the Behavior section of the text view's Attributes inspector:
I am creating a app in which i use several UITextfield's. I know how to change the placeholder colour of a single text field.
textField.attributedPlaceholder = NSAttributedString(string: "Username", attributes: [NSForegroundColorAttributeName: UIColor.redColor()]).
But i want to change the placeholder colour of all the UITextFields in the whole app. My app has more than 50 UIViewControllers and more than 25 of them has textFields(2 to 22 per screen). I want a code that can be used globally in one place so that i don't need to go to every view controller and change it manually.
If you have any other alternatives to make the job done please let me know.
I am using xcode 7.1.1 swift 2.0
Update:
For default the Placeholder colour is set to light grey colour. Is there any way for us to tweak that default behaviour and change it to any other colour?
How can we access this default code and change it?
Create the extension method
extension String {
func toAttributedString(font font:UIFont!, kerning: CGFloat!, color:UIColor!) -> NSAttributedString {
return NSAttributedString(string: self as String, font: font, kerning: kerning, color: color)!
}
}
extension NSAttributedString {
convenience init?(string text:String, font:UIFont!, kerning: CGFloat!, color:UIColor!) {
self.init(string: text, attributes: [NSKernAttributeName:kerning, NSFontAttributeName:font, NSForegroundColorAttributeName:color])
}
}
Example usage
/ Example Usage
var testString: String = "Hi Kautham"
var testAttributedString: NSAttributedString = testString.toAttributedString(font: UIFont.boldSystemFontOfSize(20), kerning: 2.0, color: UIColor.whiteColor())
let label = UILabel(frame: CGRect(x: 50, y: 50, width: 200, height: 20))
label.attributedText = testAttributedString
self.view.addSubview(label)
Declare a Macro with your NSAttributedString.
Give that Attributed string to all textfields wherever you want.
So that when you change in Macro, will reflect in all places..
Check out the following.
let CommonTextFieldAttr : NSDictionary = [NSForegroundColorAttributeName:UIColor.redColor()]
And Use it in Textfield properties.
textField?.attributedPlaceholder = NSAttributedString(string: "sdfa",attributes: CommonTextFieldAttr as? [String : AnyObject])
Hope it helps..