Reputation: 10739
I need to achieve something exactly like NSLineBreakByTruncatingHead
for UITextField
as shown here. Let's assume the original text is:
This is the long text that cannot be shown inside a UITextField
I need it like:
...cannot be shown inside a UITextField
but currently I am getting something like:
This is the long text that cannot...
simply the truncation at the beginning. The lineBreakMode
property is not given for UITextField
. How can I achieve it?
Upvotes: 3
Views: 1164
Reputation: 7718
I had a similar requirement, I wrote a Swift version of @Stonz2 solution, it worked most of the times, havent used in production yet as the requirement was removed later... anyways posting it here
extension String {
func stringByTruncatingLeadingForWidth(width: CGFloat, withFont font: UIFont) -> String{
var modifiedString = self
var mutableWidth = width
let ellipsis = "..."
if (self.widthOfString(usingFont: font) > width) {
let ellipsisWidth = ellipsis.widthOfString(usingFont: font)
// else this will go for infinite loop...mutable width will go -ve
if mutableWidth > ellipsisWidth {
mutableWidth -= ellipsis.widthOfString(usingFont: font)
}
let range = NSMakeRange(0, 1)
while modifiedString.widthOfString(usingFont: font) > mutableWidth {
modifiedString.deleteCharactersInRange(range: range)
print(modifiedString)
print(mutableWidth)
}
guard let swiftRange = Range(NSMakeRange(0, 3), in: modifiedString) else { return "" }
modifiedString.replaceSubrange(swiftRange, with: [".",".","."])
}
return modifiedString
}
func widthOfString(usingFont font: UIFont) -> CGFloat {
let fontAttributes = [NSAttributedString.Key.font: font]
let size = self.size(withAttributes: fontAttributes)
return size.width
}
mutating func deleteCharactersInRange(range: NSRange) {
guard let swiftRange = Range(range, in: self) else { return }
self.removeSubrange(swiftRange)
}
}
var str1 = "Hello how are you"
let newStr = str1.stringByTruncatingLeadingForWidth(width: 100, withFont: .systemFont(ofSize: 15))
Upvotes: 0
Reputation: 6396
I took the solution here and modified it to truncate the head of a string instead of the tail. Know that it only shows the ellipsis when the field is not being edited.
NOTE: This solution is for iOS 7+ only. To use in iOS 6, use sizeWithFont:
instead of sizeWithAttributes:
in the NSString+TruncateToWidth.m file.
EDIT: Added support for iOS 6
NSString+TruncateToWidth.h
@interface NSString (TruncateToWidth)
- (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(UIFont *)font;
@end
NSString+TruncateToWidth.m
#import "NSString+TruncateToWidth.h"
#define ellipsis @"…"
@implementation NSString (TruncateToWidth)
- (NSString*)stringByTruncatingToWidth:(CGFloat)width withFont:(UIFont *)font
{
// Create copy that will be the returned result
NSMutableString *truncatedString = [self mutableCopy];
// Make sure string is longer than requested width
if ([self widthWithFont:font] > width)
{
// Accommodate for ellipsis we'll tack on the beginning
width -= [ellipsis widthWithFont:font];
// Get range for first character in string
NSRange range = {0, 1};
// Loop, deleting characters until string fits within width
while ([truncatedString widthWithFont:font] > width)
{
// Delete character at beginning
[truncatedString deleteCharactersInRange:range];
}
// Append ellipsis
[truncatedString replaceCharactersInRange:NSMakeRange(0, 0) withString:ellipsis];
}
return truncatedString;
}
- (CGFloat)widthWithFont:(UIFont *)font
{
if([self respondsToSelector:@selector(sizeWithAttributes:)])
return [self sizeWithAttributes:@{NSFontAttributeName:font}].width;
return [self sizeWithFont:font].width;
}
Using it:
...
// Make sure to import the header file where you want to use it
// assumes instance variable holds your string that populates the field
fieldString = @"abcdefghijklmnopqrstuvwxyz1234567890";
// Size will need to be less than text field's width to account for padding
_myTextField.text = [fieldString stringByTruncatingToWidth:(_myTextField.frame.size.width - 15) withFont:_myTextField.font];
...
// use textFieldShouldBeginEditing to make it animate from the start of the field to the end of the string if you prefer that. I found it a little distracting
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
textField.text = fieldString;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
fieldString = textField.text;
textField.text = [textField.text stringByTruncatingToWidth:(textField.frame.size.width - 15) withFont:textField.font];
return YES;
}
Upvotes: 3