how can i get the fonts attributed - ios

i've a single UIButton to set the text bold and unbold in UITextview
let range = mainTextView.selectedRange
let string = NSMutableAttributedString(attributedString: mainTextView.attributedText)
let attributes = [NSFontAttributeName: UIFont.boldSystemFontOfSize(12)]
string.addAttributes(attributes, range: mainTextView.selectedRange)
mainTextView.attributedText = string
My question is how to unbold the selected text if it is already bold? how to check if the selectedRange is already bold or not?

Related

Keeping track of and changing color of text in UITextView

As the user is types in a textview, I am looking at each word and see it matches words in an array I have. If there's a match, the word is changed to blue and a boolean variable didFindACertainWord is set to true (to make sure only one word is blue). I was able to do this part successfully with a few errors:
The certain word I changed to blue works, but the words typed before font is changed and anything I type after the word is blue too (which I do not want). I only want to change the certain word to blue and keep the other words black color and same font as before.
I can not figure out how to find out if the user deleted the certain word. If they do, I want to change the color of the certain word back to to black (after they deleted the first character of the certain word) and set didFindACertainWord to false.
Here's my current code in my textViewDidChange method:
func textViewDidChange(_ textView: UITextView) {
//get last word typed
let size = textView.text.reversed().firstIndex(of: " ") ?? textView.text.count
let startWord = textView.text.index(textView.text.endIndex, offsetBy: -size)
let lastWord = textView.text[startWord...]
//check if last word is in array and we did not already find one
if certainWords.contains(String(lastWord)) && !didFindACertainWord {
didFindACertainWord = true
//change color of the word
let attributedString = NSMutableAttributedString.init(string: textView.text)
let range = (textView.text as NSString).range(of: String(lastWord))
attributedString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.blue, NSAttributedString.Key.font: UIFont(name: "Avenir-Roman", size: 18)], range: range)
textView.attributedText = attributedString
}
}
What am I missing / how can I do this successfully? P.S. the font of all text in the textview should be UIFont(name: "Avenir-Roman", size: 18)
I am searching each word because after the user types an action word, I need to read the next words if they're related to the action word to bold them. For example if the user types "see Paris London Berlin to find the best food", the action word is "see" and the related words to be bolded are the places "Paris Italy France" and the words not related (will be in regular font) are "to find the best"
For the first issue, it's because you should do an "else" case, and reset the color and the boolean value.
You should add:
} else {
didFindACertainWord = false
textView.attributedText = attributedString
}
For the second one, you shouldn't need to keep working only on the last word, instead check if there is a match in the whole string.
Not tested, but it should to the work:
func textViewDidChange(_ textView: UITextView) {
let attributedString = NSMutableAttributedString(string: textView.text,
attributes: [.font: UIFont(name: "Avenir-Roman", size: 18)])
let allWords = attributedString.string.components(separatedBy: CharacterSet.whitespaces)
if let firstMatch = allWords.first(where: { return certainWords.contains($0)}) {
didFindACertainWord = true
let firstMatchRange = (attributedString.string as NSString).range(of: firstMatch)
attributedString.addAttribute(.foregroundColor, value: UIColor.blue, range: firstMatchRange)
} else {
didFindACertainWord = false
}
textView.attributedText = attributedString
}

iOS: insert attributed string at cursor for UITextView?

UITextView lets you insert plain text at the cursor with the insertText function. Is there a clean way to do so with attributed text?
Is the only approach to split the attributedText property into two parts -- pre-cursor and post-cursor -- then append the new attributed string to the pre-cursor attributed text, followed by appending the post-cursor attributed text?
Insert into a mutable copy of the text view’s attributed text by calling https://developer.apple.com/documentation/foundation/nsmutableattributedstring/1414947-insert.
As advised by #matt, here's a Swift 4.x function:
fileprivate func insertAtTextViewCursor(attributedString: NSAttributedString) {
// Exit if no selected text range
guard let selectedRange = textView.selectedTextRange else {
return
}
// If here, insert <attributedString> at cursor
let cursorIndex = textView.offset(from: textView.beginningOfDocument, to: selectedRange.start)
let mutableAttributedText = NSMutableAttributedString(attributedString: textView.attributedText)
mutableAttributedText.insert(attributedString, at: cursorIndex)
textView.attributedText = mutableAttributedText
}

Failing to create a strikethrough on part of the text

I am trying to create a strikethrough effect on part of a UILabel text, so fat without success. I have noticed that I can create this effect on ALL the text, but not just part of it. Here's what I have
let text = "\(20.4$) \(On Rush Hour)"
let attrStr = NSMutableAttributedString(string: text)
let range = (text as NSString).range(of: "20.4$")
attrStr.addAttribute(NSStrikethroughStyleAttributeName,
value: NSUnderlineStyle.styleSingle.rawValue,
range: range)
self.originalPriceLabel.attributedText = attrStr
Now, if I only replace
let range = (text as NSString).range(of: "20.4$")
with
let range = (text as NSString).range(of: text)
I see the strikethrough. What am I doing wrong?
Thanks!

How to make bold a part of NSMutableString?

I have this code in my hands:
if let text = trimText?.mutableCopy() as? NSMutableString {
text.insertString("\(prefix) ", atIndex: 0)
textStorage.replaceCharactersInRange(range, withString: text as String)
}
When I try to change my text as:
text = attributedTextFunc(text)
where
func attributedTextFunc(str: NSString) -> NSAttributedString {
var attributedString = NSMutableAttributedString(string: str as String, attributes: [NSFontAttributeName:UIFont.systemFontOfSize(15.0)])
let boldFontAttribute = [NSFontAttributeName: UIFont.boldSystemFontOfSize(15.0)]
attributedString.addAttributes(boldFontAttribute, range: str.rangeOfString("More"))
return attributedString
}
and I get this error:
Cannot assign value of type 'NSAttributedString' to type 'NSMutableString'
How can I make it bold?
You cannot assing NSAttributedString to text. It's two different types.
String is not subclassed from NSAttributedString.
You should set:
attributedText = attributedTextFunc(text)
Then if you want to present it on UILabel
label.attributedText = attributedText
UPDATE
Struct String doesn't know anything about UIKit and Bold styles.
NSAttributedString knows about UIKit and contains any text styles you want
UPDATE 2
In your case
ReadMoreTextView.attributedTrimText = attributedText
You cannot reassign text because:
text is constant (let)
text is NSMutableString, but attributedTextFunc return NSAttributedString
You have to store result of attributedTextFunc in variable as a NSAttributeString and set attributeText of UILabel instead of text
if let text = trimText?.mutableCopy() as? NSMutableString {
// ...
let attributeText = attributedTextFunc(text)
someLabel.attributeText = attributeText
}
Use this code and pass your normal String and Bold String (which is needed to be bold).
func attributeStrings(first: String, second : String) -> NSMutableAttributedString{
let myNormalAttributedTitle = NSAttributedString(string: first,
attributes: [NSFontAttributeName : UIFont.boldSystemFontOfSize(15)])
let myAttributedTitle = NSAttributedString(string: second,
attributes: [NSForegroundColorAttributeName : UIColor.blackColor()])
let result = NSMutableAttributedString()
result.appendAttributedString(myNormalAttributedTitle)
result.appendAttributedString(myAttributedTitle)
return result
}
and assign the return value of this function to
someLabel.attributeText = attributeStrings("My Name is", second : "Himanshu")
It is because, your text is type of NSMutableString and your function attributedTextFunc is type of NSString.
That is the problem so just change it from NSString to NSMutableString.

how to print formated text from keyboard

I was wondering how can I print formated text from the keyboard keys. For example, I have a toolbar attached to the keyboard, I click "bold" on the keyboard and from there on every letter printed from the keyboard will now be bold. This is what I have but it does not work, String's don't seem to hold format.
func keyPressed(sender: AnyObject?) {
let button = sender as! UIButton
let title = button.titleForState(.Normal)
let attrs = [NSFontAttributeName : UIFont.boldSystemFontOfSize(15)]
let boldString = NSMutableAttributedString(string:title!, attributes:attrs)
(textDocumentProxy as UIKeyInput).insertText(boldString.string)
}
Strings don't hold format, you're right. You should manipulate your target directly, using NSAttributedString and attributedText to do so.
let str = "Hello, world!"
let attrs = [NSFontAttributeName: UIFont.systemFontOfSize(15)]
let attributedString = NSAttributedString(string: str, attributes: attrs)
yourTextView.attributedText = attributedString
Note that the specific thing you want to do is tricky, because attributed strings attach attributes (like bold) to parts of text and not "from there on every letter". So if you read out the current attributed string then try to modify the attributes at the caret without actually inserting anything, it won't work.
So, this won't work:
let existingAttributedString = yourTextView.attributedText.mutableCopy() as! NSMutableAttributedString
let newAttrs = [NSFontAttributeName: UIFont.boldSystemFontOfSize(15)]
let newAttributedString = NSAttributedString(string: "", attributes: newAttrs)
existingAttributedString.appendAttributedString(newAttributedString)
Whereas this will:
let existingAttributedString = yourTextView.attributedText.mutableCopy() as! NSMutableAttributedString
let newAttrs = [NSFontAttributeName: UIFont.boldSystemFontOfSize(15)]
let newAttributedString = NSAttributedString(string: " ", attributes: newAttrs)
existingAttributedString.appendAttributedString(newAttributedString)
The only difference is that the second example inserts a space, which is enough for iOS to attach attributes to.
That being said, if you're willing to change your approach so that users select existing text before hitting bold, that works great.

Resources