Reputation: 4550
I'm using storyboard to set number of lines(4) of UILabel
and line breaking(truncate tails).
This is what i have right now:
My question is how do I truncate/trigger truncate?
This is what i want to achieve:
Update:
Just to make my question clearer.
I dont want to cut the actual string in the UILabel
like how the default UILabel
behaves.
The log produced by the first image when using NSLog(@"%@", myLabel.text);
is the complete string assigned to it, and that is behavior i'm trying to achieve.
In my example it's:
A little girl was talking to her teacher about whales. The teacher said it was physically impossible for a whale to swallow a human because even though it was a very large mammal.
Making my question clearer:
How do I truncate/trigger truncate without cutting the actual NSString
assigned to it?
or maybe a work around that will lead to that, this is possible right?
Upvotes: 3
Views: 1776
Reputation: 1640
I use Associated Objects and Method Swizzling to implement that. Inheritance maybe better than category in this case. It's up to you.
UILabel+Display.h:
#import <UIKit/UIKit.h>
@interface UILabel (Display)
@end
UILabel+Display.m:
#import "UILabel+Display.h"
#import <objc/runtime.h>
@implementation UILabel (Display)
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(setText:);
SEL swizzledSelector = @selector(setDisplayText:);
[self swizzleeClass:class selector:originalSelector replaceSeletor:swizzledSelector];
SEL textSelector = @selector(text);
SEL swizzledTextSelector = @selector(originText);
[self swizzleeClass:class selector:textSelector replaceSeletor:swizzledTextSelector];
});
}
- (NSString *)originText
{
return objc_getAssociatedObject(self, @selector(originText));
}
- (void)setDisplayText:(NSString *)text
{
objc_setAssociatedObject(self, @selector(originText), text, OBJC_ASSOCIATION_COPY);
UIFont *font = self.font;
NSDictionary *attributes = @{NSFontAttributeName:font};
CGRect bounds = self.bounds;
CGFloat width = CGRectGetWidth(bounds);
CGFloat height = CGRectGetHeight(bounds);
CGSize maxSize = CGSizeMake(width, CGFLOAT_MAX);
NSStringDrawingOptions drawOptions = NSStringDrawingUsesLineFragmentOrigin;
CGRect rect = [text boundingRectWithSize:maxSize
options:drawOptions
attributes:attributes
context:nil];
CGFloat needHeight = CGRectGetHeight(rect);
NSString *tipText = @" ... continue reading";
NSUInteger index = text.length-1;
NSString *displayText = text;
while (needHeight>height) {
displayText = [[text substringToIndex:index]stringByAppendingString:tipText];
rect = [displayText boundingRectWithSize:maxSize
options:drawOptions
attributes:attributes
context:nil];
needHeight = CGRectGetHeight(rect);
//needHeight = [displayText sizeWithFont:font constrainedToSize:maxSize lineBreakMode:NSLineBreakByWordWrapping].height; //NS_DEPRECATED_IOS(2_0, 7_0)
index--;
}
[self setDisplayText:displayText];
}
+ (void)swizzleeClass:(Class)class selector:(SEL)originalSelector replaceSeletor:(SEL)swizzledSelector
{
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
@end
Note I don't handle short text condition and attributed string.
Upvotes: 1
Reputation: 23882
You can use TTTAttributedLabel library
For example :
Declaration :
@property (strong, nonatomic) IBOutlet TTTAttributedLabel *lblTT;
Example Code with setAttributedTruncationToken
:
NSDictionary *attr = @{NSForegroundColorAttributeName : [UIColor redColor]};
NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"...Continue Reading" attributes:attr];
[self.lblTT setAttributedTruncationToken:str];
Hope it will help you.
If you don't want to use ready made class, Please check this answer : How to add button to the end of text like Facebook's "Continue reading"?
Upvotes: 2