Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
222 views
in Technique[技术] by (71.8m points)

ios - Decrease the width of the last line in multiline UILabel

I am implemententing a "read more" functionality much like the one in Apple's AppStore. However, I am using a multiline UILabel. Looking at Apple's AppStore, how do they decrease the last visible line's width to fit the "more" text and still truncate the tail (see image)?

iBooks example image from AppStore

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This seems to work, at least with the limited amount of testing I've done. There are two public methods. You can use the shorter one if you have multiple labels all with the same number of lines -- just change the kNumberOfLines at the top to match what you want. Use the longer method if you need to pass the number of lines for different labels. Be sure to change the class of the labels you make in IB to RDLabel. Use these methods instead of setText:. These methods expand the height of the label to kNumberOfLines if necessary, and if still truncated, will expand it to fit the whole string on touch. Currently, you can touch anywhere in the label. It shouldn't be too hard to change that so only touches near the ...Mer would cause the expansion.

#import "RDLabel.h"
#define kNumberOfLines 2
#define ellipsis @"...Mer ? "

@implementation RDLabel {
    NSString *string;
}

#pragma Public Methods

- (void)setTruncatingText:(NSString *) txt {
    [self setTruncatingText:txt forNumberOfLines:kNumberOfLines];
}

- (void)setTruncatingText:(NSString *) txt forNumberOfLines:(int) lines{
    string = txt;
    self.numberOfLines = 0;
    NSMutableString *truncatedString = [txt mutableCopy];
    if ([self numberOfLinesNeeded:truncatedString] > lines) {
        [truncatedString appendString:ellipsis];
        NSRange range = NSMakeRange(truncatedString.length - (ellipsis.length + 1), 1);
        while ([self numberOfLinesNeeded:truncatedString] > lines) {
            [truncatedString deleteCharactersInRange:range];
            range.location--;
        }
        [truncatedString deleteCharactersInRange:range];  //need to delete one more to make it fit
        CGRect labelFrame = self.frame;
        labelFrame.size.height = [@"A" sizeWithFont:self.font].height * lines;
        self.frame = labelFrame;
        self.text = truncatedString;
        self.userInteractionEnabled = YES;
        UITapGestureRecognizer *tapper = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(expand:)];
        [self addGestureRecognizer:tapper];
    }else{
        CGRect labelFrame = self.frame;
        labelFrame.size.height = [@"A" sizeWithFont:self.font].height * lines;
        self.frame = labelFrame;
        self.text = txt;
    }
}

#pragma Private Methods

-(int)numberOfLinesNeeded:(NSString *) s {
    float oneLineHeight = [@"A" sizeWithFont:self.font].height;
    float totalHeight = [s sizeWithFont:self.font constrainedToSize:CGSizeMake(self.bounds.size.width, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping].height;
    return nearbyint(totalHeight/oneLineHeight);
}

-(void)expand:(UITapGestureRecognizer *) tapper {
    int linesNeeded = [self numberOfLinesNeeded:string];
    CGRect labelFrame = self.frame;
    labelFrame.size.height = [@"A" sizeWithFont:self.font].height * linesNeeded;
    self.frame = labelFrame;
    self.text = string;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...