Add "...Read More" to the end of UILabel Add "...Read More" to the end of UILabel ios ios

Add "...Read More" to the end of UILabel


Swift4 (IOS 11.2)

Readmore at the end of the label without action

extension UILabel {    func addTrailing(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor) {        let readMoreText: String = trailingText + moreText        let lengthForVisibleString: Int = self.visibleTextLength        let mutableString: String = self.text!        let trimmedString: String? = (mutableString as NSString).replacingCharacters(in: NSRange(location: lengthForVisibleString, length: ((self.text?.count)! - lengthForVisibleString)), with: "")        let readMoreLength: Int = (readMoreText.count)        let trimmedForReadMore: String = (trimmedString! as NSString).replacingCharacters(in: NSRange(location: ((trimmedString?.count ?? 0) - readMoreLength), length: readMoreLength), with: "") + trailingText        let answerAttributed = NSMutableAttributedString(string: trimmedForReadMore, attributes: [NSAttributedStringKey.font: self.font])        let readMoreAttributed = NSMutableAttributedString(string: moreText, attributes: [NSAttributedStringKey.font: moreTextFont, NSAttributedStringKey.foregroundColor: moreTextColor])        answerAttributed.append(readMoreAttributed)        self.attributedText = answerAttributed    }    var visibleTextLength: Int {        let font: UIFont = self.font        let mode: NSLineBreakMode = self.lineBreakMode        let labelWidth: CGFloat = self.frame.size.width        let labelHeight: CGFloat = self.frame.size.height        let sizeConstraint = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)        let attributes: [AnyHashable: Any] = [NSAttributedStringKey.font: font]        let attributedText = NSAttributedString(string: self.text!, attributes: attributes as? [NSAttributedStringKey : Any])        let boundingRect: CGRect = attributedText.boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, context: nil)        if boundingRect.size.height > labelHeight {            var index: Int = 0            var prev: Int = 0            let characterSet = CharacterSet.whitespacesAndNewlines            repeat {                prev = index                if mode == NSLineBreakMode.byCharWrapping {                    index += 1                } else {                    index = (self.text! as NSString).rangeOfCharacter(from: characterSet, options: [], range: NSRange(location: index + 1, length: self.text!.count - index - 1)).location                }            } while index != NSNotFound && index < self.text!.count && (self.text! as NSString).substring(to: index).boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, attributes: attributes as? [NSAttributedStringKey : Any], context: nil).size.height <= labelHeight            return prev        }        return self.text!.count    }}

Swift 4.2

extension UILabel {        func addTrailing(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor) {            let readMoreText: String = trailingText + moreText            let lengthForVisibleString: Int = self.vissibleTextLength            let mutableString: String = self.text!            let trimmedString: String? = (mutableString as NSString).replacingCharacters(in: NSRange(location: lengthForVisibleString, length: ((self.text?.count)! - lengthForVisibleString)), with: "")            let readMoreLength: Int = (readMoreText.count)            let trimmedForReadMore: String = (trimmedString! as NSString).replacingCharacters(in: NSRange(location: ((trimmedString?.count ?? 0) - readMoreLength), length: readMoreLength), with: "") + trailingText            let answerAttributed = NSMutableAttributedString(string: trimmedForReadMore, attributes: [NSAttributedString.Key.font: self.font])            let readMoreAttributed = NSMutableAttributedString(string: moreText, attributes: [NSAttributedString.Key.font: moreTextFont, NSAttributedString.Key.foregroundColor: moreTextColor])            answerAttributed.append(readMoreAttributed)            self.attributedText = answerAttributed        }        var vissibleTextLength: Int {            let font: UIFont = self.font            let mode: NSLineBreakMode = self.lineBreakMode            let labelWidth: CGFloat = self.frame.size.width            let labelHeight: CGFloat = self.frame.size.height            let sizeConstraint = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude)            let attributes: [AnyHashable: Any] = [NSAttributedString.Key.font: font]            let attributedText = NSAttributedString(string: self.text!, attributes: attributes as? [NSAttributedString.Key : Any])            let boundingRect: CGRect = attributedText.boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, context: nil)            if boundingRect.size.height > labelHeight {                var index: Int = 0                var prev: Int = 0                let characterSet = CharacterSet.whitespacesAndNewlines                repeat {                    prev = index                    if mode == NSLineBreakMode.byCharWrapping {                        index += 1                    } else {                        index = (self.text! as NSString).rangeOfCharacter(from: characterSet, options: [], range: NSRange(location: index + 1, length: self.text!.count - index - 1)).location                    }                } while index != NSNotFound && index < self.text!.count && (self.text! as NSString).substring(to: index).boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, attributes: attributes as? [NSAttributedString.Key : Any], context: nil).size.height <= labelHeight                return prev            }            return self.text!.count        }    }

Usage

let readmoreFont = UIFont(name: "Helvetica-Oblique", size: 11.0)let readmoreFontColor = UIColor.blueDispatchQueue.main.async {    self.yourLabel.addTrailing(with: "... ", moreText: "Readmore", moreTextFont: readmoreFont!, moreTextColor: readmoreFontColor)}

Result

Readmore label output

NOTE: - Action is not included for Readmore


So this is what I did to add the Read More... button to the UITextView, UITextField or UILabel:

- (void)addReadMoreStringToUILabel:(UILabel*)label{    NSString *readMoreText = @" ...Read More";    NSInteger lengthForString = label.text.length;    if (lengthForString >= 30)    {        NSInteger lengthForVisibleString = [self fitString:label.text intoLabel:label];        NSMutableString *mutableString = [[NSMutableString alloc] initWithString:label.text];        NSString *trimmedString = [mutableString stringByReplacingCharactersInRange:NSMakeRange(lengthForVisibleString, (label.text.length - lengthForVisibleString)) withString:@""];        NSInteger readMoreLength = readMoreText.length;        NSString *trimmedForReadMore = [trimmedString stringByReplacingCharactersInRange:NSMakeRange((trimmedString.length - readMoreLength), readMoreLength) withString:@""];        NSMutableAttributedString *answerAttributed = [[NSMutableAttributedString alloc] initWithString:trimmedForReadMore attributes:@{                                                                                                                                        NSFontAttributeName : label.font                                                                                                                                        }];        NSMutableAttributedString *readMoreAttributed = [[NSMutableAttributedString alloc] initWithString:readMoreText attributes:@{                                                                                                                                        NSFontAttributeName : Font(TWRegular, 12.),                                                                                                                                        NSForegroundColorAttributeName : White                                                                                                                                        }];        [answerAttributed appendAttributedString:readMoreAttributed];        label.attributedText = answerAttributed;        UITagTapGestureRecognizer *readMoreGesture = [[UITagTapGestureRecognizer alloc] initWithTarget:self action:@selector(readMoreDidClickedGesture:)];        readMoreGesture.tag = 1;        readMoreGesture.numberOfTapsRequired = 1;        [label addGestureRecognizer:readMoreGesture];        label.userInteractionEnabled = YES;    }    else {        NSLog(@"No need for 'Read More'...");    }}

There is a use of fitString:intoLabel method which can be found here.

As for the UITagTapGestureRecognizer is just a normal UITapGestureRecognizer subclass with a NSInteger property called tag. I did that because I want to identify which Read More... were clicked in I case I have more than one in the same UIViewController. You can use a normal UITapGestureRecognizer.

Enjoy!


Tttattributed label has this feature

https://github.com/TTTAttributedLabel/TTTAttributedLabel

You need to set the "truncation" token as "read more..."

See

attributedTruncationToken

var subTitleLabel = TTTAttributedLabel(frame : frame)    self.addSubview(subTitleLabel)    var trunc = NSMutableAttributedString(string: "...more")    trunc.addAttribute(NSFontAttributeName, value: UIFont.systemFontOfSize(12), range: NSMakeRange(0, 7))    trunc.addAttribute(NSForegroundColorAttributeName, value: UIColor.blueColor(), range: NSMakeRange(0, 7))    subTitleLabel.attributedTruncationToken = trunc    subTitleLabel.numberOfLines = 1    subTitleLabel.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth