Add '...' After UILabel Word Wrapped Property - ios

I have a UILabel that has max-lines of 2, and a word wrapping property. This is done in storyboard.
I need to add a '...' after the last wrapped word on those labels that end up being word wrapped.
Is this possible? I have tried some solutions from around the internet, but they seem to have not worked. Those include:
Testing label if it has been truncated, and appending '...' to those that have been.
Programmatically using attributed text to hijack storyboard.
Tried using Truncate Tail - Unable to use this because it cuts the word off like so "Highli...".

I think I understand what you are trying to do. This is a bit sloppy, but it should work
extension UILabel {
func truncateAndFitText()
{
if let string = self.text
{
let words = string.components(separatedBy: " ")
var lastString = ""
var tempString = ""
for word in words
{
(tempString == "") ? tempString.append(word) : tempString.append(" \(word)")
let size: CGSize = tempString.size(attributes: [NSFontAttributeName: self.font])
if (size.width > (self.bounds.size.width * CGFloat(self.numberOfLines)))
{
lastString.append("...")
break
}
else
{
lastString = tempString
}
}
self.text = lastString
}
}
}
and then use it like
myLabel.truncateAndFitText

Related

swift: edit text in JSON

I have JSON file with text and label. In JSON file I want to add this characters <b> or <i> to some words. For example:
"this is my text <b>bold<b> or <i>italic<i>"
And before when I show text in label I want to analyse my text and if some words have this characters <b> or <i> I want to make this word bold or italic in the text of the label. How to do it? Or there are another way to make bold text from JSON?
UPDATE:
Yours code:
/* Set Tagged Text & Fonts */
let taggedTextString = myText.text
let tagFont = UIFont.boldSystemFont(ofSize: 17.0)
let normalFont = UIFont.systemFont(ofSize: 17.0)
/* You can simply assign the AttributedText to the modified String, which may return nil. */
textLabel.attributedText = taggedTextString.modifyFontWithTags(openingTag: "<tag>", closingTag: "</tag>", taggedFont: tagFont, unTaggedFont: normalFont)
My code:
var attributedString = NSMutableAttributedString(string: myText.text)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 5
attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
textLabel.attributedText = attributedString;
Is this code the best way to union your and my code?
for i in stride(from: 0, to: allTagsSplitArray.count, by: 1) {
finalAttrStr.append(NSMutableAttributedString(string: allTagsSplitArray[i], attributes: [kCTFontAttributeName as NSAttributedStringKey : i % 2 == 0 ? untaggedTextFont : taggedTextFont]))
// my code
finalAttrStr.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, finalAttrStr.length))
}
The simplest way I seem to have accomplished this is by running through the string and scanning for your key tags - <b>, <i>, etc.
To make things easier (and more reusable), we should make an extension of our String or NSAttributedString classes. For this example, I've extended the String class, and and I return a NSAttributedString:
func modifyFontWithTags(openingTag: String, closingTag: String, taggedFont: UIFont?, unTaggedFont: UIFont?) -> NSMutableAttributedString? {
/* Make sure we have everything we need. */
guard let taggedTextFont = taggedFont,
let untaggedTextFont = unTaggedFont,
!self.isEmpty,
self.contains(openingTag),
self.contains(closingTag) else { return nil }
/* Split the string up using our closing tag. */
let closingTagSplitArray = self.components(separatedBy: closingTag)
/* Make a placeholder array. */
var allTagsSplitArray = [String]()
/* Iterate through our split array. */
for item in closingTagSplitArray {
if item.contains(openingTag) {
/* Strip the opening tag & append. */
allTagsSplitArray.append(contentsOf: item.components(separatedBy: openingTag))
} else {
/* Just append. */
allTagsSplitArray.append(item)
}
}
/* Instantiate our attributed string. */
let finalAttrStr = NSMutableAttributedString()
for i in stride(from: 0, to: allTagsSplitArray.count, by: 1) {
/* Add our font to every-other item in the array (the tagged portions). */
finalAttrStr.append(NSMutableAttributedString(string: allTagsSplitArray[i], attributes: [NSFontAttributeName : i % 2 == 0 ? untaggedTextFont : taggedTextFont]))
}
return finalAttrStr
}
Note: In this example, I take in an UIFont parameter, but you can modify this function to take in whatever attribute types you want.

Swift filling textView

How can I fill my textView with restraints so that each string "test" print all the way down the textView. Example in the picture.
-Trying to match "Test" with percentages.
for _ in 1...100{
profitLoss.text = "Test\n"
}
you have to add each string to previous string, run this code in swift play ground it will help you to understand.
var finalString = "1%"
for i in 2...100 {
finalString += "\n\(i)%"
}
print(finalString)
profitLoss.text = finalString
Build your string first, then set it to the textView's text:
var test = "Test"
for _ in 1...99 {
test += "\nTest"
}
profitLoss.text = test
It's not good way as per your image that attached but you can achaive it by below
var strText = "Text \n"
for _ in 1...100 {
txtView.text = strText.appending(strText)
}

Syntax-highlighting Text With a Custom List of Keywords

I'm working on a macOS application. I need to syntax-highlight text that is placed over TextView (NSTextView) with a list of selected words. For simplicity, I'm actually testing the same feature on the iPhone Simulator. Anyway, a list of words to highlight comes as a form of an array. The following is what I have.
func HighlightText {
let tagArray = ["let","var","case"]
let style = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle
style.alignment = NSTextAlignment.Left
let words = textView.string!.componentsSeparatedByString(" ") // textView.text (UITextView) or textView.string (NSTextView)
let attStr = NSMutableAttributedString()
for i in 0..<words.count {
let word = words[i]
if HasElements.containsElements(tagArray,text: word,ignore: true) {
let attr = [
NSForegroundColorAttributeName: syntaxcolor,
NSParagraphStyleAttributeName: style,
]
let str = (i != words.count-1) ? NSAttributedString(string: word.stringByAppendingString(" "), attributes: attr) : NSAttributedString(string: word, attributes: attr)
attStr.appendAttributedString(str)
} else {
let attr = [
NSForegroundColorAttributeName: NSColor.blackColor(),
NSParagraphStyleAttributeName: style,
]
let str = (i != words.count-1) ? NSAttributedString(string: word.stringByAppendingString(" "), attributes: attr) : NSAttributedString(string: word, attributes: attr)
attStr.appendAttributedString(str)
}
}
textView.textStorage?.setAttributedString(attStr)
}
class HasElements {
static func containsElements(array:Array<String>,text:String,ignore:Bool) -> Bool {
var has = false
for str in array {
if str == text {
has = true
}
}
return has
}
}
The simple methodology here is to separate the entire string of text into words with a white space (" ") and puts each word in an array (words). The containsElements function simply tells whether or not the selected word contains one of the keywords in the array (tagArray). If it returns true, the word is put in an NSMutableAttributedString with a highlight color. Otherwise, it's put in the same attributed string with a plain color.
The problem with this simple methodology is that a separated word puts the last word and /n and the next word together. For example, if I have a string like
let base = 3
let power = 10
var answer = 1
, only the first 'let' will be highlighted as the code puts 3 and the next let together like '3\nlet.' If I separate any word containing \n with a fast enumeration, the code won't detect each new paragraph well. I appreciate any advice to make it better. Just FYI, I'm going to leave this topic open to both macOS and iOS.
Muchos thankos
Couple different options. String has a function called componentsSeparatedByCharactersInSet that allows you to separate by a character set you define. Unfortunately this won't work since you want to separate by \n which is more than one character.
You could split the words twice.
let firstSplit = textView.text!.componentsSeparatedByString(" ")
var words = [String]()
for word in firstSplit {
let secondSplit = word.componentsSeparatedByString("\n")
words.appendContentsOf(secondSplit)
}
But then you wouldn't have any sense of the line breaks.. You'd need to re add them back in.
Finally, the easiest hack is simply:
let newString = textView.text!.stringByReplacingOccurrencesOfString("\n", withString: "\n ")
let words = newString.componentsSeparatedByString(" ")
So basically you add your own spaces.

Showing Multiple Lines in a TextView

I am doing a project in Swift and I am reading data from a file and trying to display it in a text view. I am reading it line by line. For example, if I have 10 lines in the file the text view only shows the last one. And I'd like to see them all.
How can I do that?
I am doing it like this:
if let aStreamReader = StreamReader(path: "historic.txt") {
defer {
aStreamReader.close()
}
while let line = aStreamReader.nextLine() {
MyTextView.text = "\(line)"
}
The code is working in the console, because if I make a print every show up ok.
But in the text view only last line is visible.
How about trying:
MyTextView.text += "(line)"
The '+' will append rather than replace.
You might have to add \n after the lines string to create a new line:
MyTextView.text += "(line) \n"
Update:
I forgot you can't append onto a textview, so instead create an empty string before the loop and then append the line onto the string in the while loop. Then finally set the textview text to the totalString variable after the loop:
var totalString = ""
while let line = aStreamReader.nextLine() {
totalString = totalString + line + "\n"
}
MyTextView.text = totalString
Hope that helps
Make sure the value of lines property of label is 0 and try this
if let aStreamReader = StreamReader(path: "historic.txt") {
defer {
aStreamReader.close()
}
var str = ""
while let line = aStreamReader.nextLine() {
str = str + line + "\n"
}
MyTextView.text = str

String formatting in Swift

I can't seem to understand why the following does not work:
var content : NSString = ""
let myLabel : UILabel = self.view.viewWithTag(i) as UILabel
content += String(format:"var %# = false;", myLabel.text)
I get the following error:
NSString is not identical to 'UInt8'
It's because NSString class doesn't support appending string using +. It only supports if you use String. You can fix that issue by:
var content : String = ""
let myLabel : UILabel = self.view.viewWithTag(i) as UILabel
content += String(format:"var %# = false;", myLabel.text!)
try using String interpolation:
content += "var \(myLabel.text) = false;"
Instead of using format, why not use Swift's string interpolation?
content += "var \(myLabel.text!) = false;"
It doesn’t give you the numeric formatting that is so useful in NSString's format, but you are just inserting a string with no formatting required.
However the use of ! without checking always makes me twitch, so how about something like:
if let labelText = myLabel.text {
content += "var \(labelText) = false;"
}

Resources