Swift - Placeholder long text - cut the middle - ios

I have UITextField with long placeholder like this:
"QWERTYUIOPASDFGHJKLZXCVBNM", but my textfield is small and when I use function textField.adjustsFontSizeToFitWidth = true the minimumFontSize that I can set is 9 but still I can't fit the text into the textField. I want to cut the middle of the text and I expect the text to be "QWERTY...CVBNM" how to do that?

func cutTheMiddleOfLongString(var string:String) -> String {
if(countElements(string)>20){
let begining = string[advance(string.startIndex, 0)..<advance(advance(string.startIndex, 0), 12)]
let ending = string[advance(string.startIndex, countElements(string)-8)..<advance(advance(string.startIndex, countElements(string)-8), 8)]
string = begining + "..." + ending
}
return string
}
This will take first 12 letters and last 8 letters of the string and will put ... between them(begining ending).

Related

swift how to get UILabel align to top left

I'm making a trivia app that prints the question out word by word, and currently it starts at the middle of the UILabel and pushes the previous text upward. I'm trying to find out if I can start the first word at the top left of the label, the continue printing the rest.
func printQuestion ()
{
var str = quizbrain.getQuestionText()
var arr = str.components(separatedBy: " ")
var count = 0
Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { (t) in
self.questionLabel.text! += " " + arr[count]
count += 1
if count == arr.count {
t.invalidate()
}
if self.hasBuzzed == true {
t.invalidate()
}
}
I'm trying to find out if I can start the first word at the top left of the label
No, you can’t. That’s not how labels draw when their text changes.
Cool workaround: start with the label containing the whole text, but use an attributed string so that the text is the same color as the background (e.g. white on white) and thus invisible. In your timer, change the color of one word at a time to black.
That way, you never change the text, just the color, so the text does not move as each word is revealed.

creating spaces in placeholder fields

my problem is I want to put 2 placeholders for one textField. one of the place holders should be on the left and the other should be on the right.
my code:
func returnPlaceHolder(first: String, second: String, textField: UITextField){
let width: Int = Int(textField.bounds.width * 0.2)
let spaceValue = width - (first.count + second.count)
var temp = "\(first) "
let tempCount = spaceValue - (first.count + second.count)
var value = String()
for _ in 0..<tempCount {
temp.append(" ")
}
value = "\(temp) \(second)"
textField.placeholder = value
textField.setLeftPaddingPoints(10)
textField.setRightPaddingPoints(10)
}
I'm currently using this function to create spaces.. but my problem is the spaces won't be the same for more than one textField, and I want them to be aligned..
just like this picture: https://imgur.com/pZZMoNv
and this is the result I'm getting for my current code: https://imgur.com/a/5AN8EXl
don't mind the textFields format & text I can fix them later.. I just want to be able to align the textFields placeholders.
It would be really hard (if possible) to achieve what you are trying to do by injecting spaces into the text because each character in the font has a different width unless you use a monospaced font.
https://en.wikipedia.org/wiki/Monospaced_font
Instead, I would recommend a different approach. Override the text field, provide two UILabels and adjust their position using Autolayout.

Read/see More at the end of the label

I am trying to create a read more button at the end of my label. I want it to display 3 lines by default. I am coding in swift not objective c. Only when the user clicks the read more part of the label, should the label expand. It should look and work exactly like it does on instagram except on Instagram, it is in a tableview cell. My label and read more button will be in a scrollview. I have managed to get the expanding and contracting part working by adjusting the number of lines property of the label.
if descriptionLabel.numberOfLines == 0{
descriptionLabel.numberOfLines = 3
}else {
descriptionLabel.numberOfLines = 0
}
descriptionLabel.lineBreakMode = NSLineBreakMode.byWordWrapping
I am having problems with putting a "...more" at the end of the label and cutting the text off at the right place. I have looked at other people's responses to similar questions but nothing seems to work properly.
I can put a button over the last line of text so making the see more part of the label clickable also isn't the problem. The problem I am having is truncating the text at the right place and placing the see more text at the right place so that it displays.
I also want the read more button to only appear when it is necessary. I don't want to it appear when there are only 1-3 lines of text. This is also something I am having issues with.
I can't use this https://github.com/apploft/ExpandableLabel because it does not support scrollviews just tableviews.
the swift solution here didn't work: Add "...Read More" to the end of UILabel. It crashed the app.
Finally, the read more button should be in line with the last line of text and at the end of it. It would be an added benefit it this worked in a tableview cell as well!
I found ReadMoreTextView in Github, which is based on UITextView. The key method in this library is the following:
private func characterIndexBeforeTrim(range rangeThatFits: NSRange) -> Int {
if let text = attributedReadMoreText {
let readMoreBoundingRect = attributedReadMoreText(text: text, boundingRectThatFits: textContainer.size)
let lastCharacterRect = layoutManager.boundingRectForCharacterRange(range: NSMakeRange(NSMaxRange(rangeThatFits)-1, 1), inTextContainer: textContainer)
var point = lastCharacterRect.origin
point.x = textContainer.size.width - ceil(readMoreBoundingRect.size.width)
let glyphIndex = layoutManager.glyphIndex(for: point, in: textContainer, fractionOfDistanceThroughGlyph: nil)
let characterIndex = layoutManager.characterIndexForGlyph(at: glyphIndex)
return characterIndex - 1
} else {
return NSMaxRange(rangeThatFits) - readMoreText!.length
}
}
To display text like "xxxx...Read More", the library
Get how many characters could be display in the UITextView: Use NSLayoutManager.characterRange(forGlyphRange:, actualGlyphRange:)
Get the position of the last visible character and the width of "...Read More": Use NSLayoutManager.boundingRect(forGlyphRange glyphRange: NSRange, in container: NSTextContainer)
Get the character index before trimming: Use NSLayoutManager.characterIndexForGlyph(at glyphIndex: Int)
Replace text which should be trimmed with "...Read More": UITextStorage.replaceCharacters(in range: NSRange, with attrString: NSAttributedString)
Please check :
func addSeeMore(str: String, maxLength: Int) -> NSAttributedString {
var attributedString = NSAttributedString()
let index: String.Index = str.characters.index(str.startIndex, offsetBy: maxLength)
let editedText = String(str.prefix(upTo: index)) + "... See More"
attributedString = NSAttributedString(string: editedText)
return attributedString
}
You can use like :
let str = "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
descriptionLabel.attributedText = addSeeMore(str: str, maxLength: 20)
// Output : Lorem Ipsum is simpl... See More

UINavigationItem title truncation

I have text that is built from two Strings:
A(B)
I want to use both strings as the title for the UINavigationItem but in case of truncation I want only A to be truncated and not B.
Example:
The title I want is "The quick brown fox jumps (over the lazy dog)".
The screen size is too small so the title truncates and it is now "The quick brown fox jumps (over...".
What I want it to be is: "The quick br... (over the lazy dog)"
How can I do that?
First check number of characters navigation bar allowing as title without truncating. Next, before setting title check whether the total string length is less than those number of characters or not. Now based on condition set either combined string or B only.
Since xcode won't be able to detect in which part of your title you want to stop and which part you want to start again, you need to do it yourself.
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Heal the world make it a better place for you and for me and the entire human race"
setNavTitle(title: self.navigationItem.title!)
}
func setNavTitle(title: String)
{
//get the last 10 characters of your title, change the number to your need
let last10 = title.substring(from:title.index(title.endIndex, offsetBy: -14))
//get the first 10 characters of your title, change the number to your need
let first10 = title.substring(to: title.index(title.startIndex, offsetBy: 14))
//concatenate the strings
let title = first10 + " ... " + last10
self.navigationItem.title = title
}

Disable Line Wrapping in a multi-line UILabel

Is there a way with a multi-line label (myLabel.numberOfLines = 0) to disable any kind of line wrapping so that if a line is too long to fit on one line of the label it just stops/kind of breaks off and doesnt wrap to the line below? So I can use "\n" to assign strings to other lines of the label. I know lines that are too long automatically wrap to the next line but I dont know if there is a no line wrap option.
So If I had a label with a line max of 10 chars per line
var firstLine : String = "This is 16 chars"
var secondLine : String = "This is too long"
myLabel.text = firstLine + secondLine
// It would look like this:
Output:
This is 16
This is to
As shown it just cuts off and doesnt wrap each line even though they dont fit
firstLine + secondLine will become 1 string This is 16 charsThis is too long, i dont think you can do something like described without code, you have to manually cut off the strings to 10 characters and add \n at the end, so it will become This is 16\nThis is to
Something like :
var string = message
let fontAttributes = [NSFontAttributeName: font]
var size = (string as NSString).sizeWithAttributes(fontAttributes)
while size.width > label.width {
string.removeAtIndex(string.endIndex.predecessor())
size = (string as NSString).sizeWithAttributes(fontAttributes)
}
string = string+"\n"
If you have desired length of your label, you can try this stupid but work method: To cut the string by yourself, use stringByPaddingToLength method.
Try below codes:
self.tempLabel.text = #"This is 16 chars fbaebfbefbefbeif";
self.tempLabel.text = [self.tempLabel.text stringByPaddingToLength:10 withString:#"" startingAtIndex:0];
See magic happens

Resources