ios 在 UILabel 末尾添加“...Read More”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32309247/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:27:55  来源:igfitidea点击:

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

iosobjective-cuilabelnsattributedstring

提问by Yossi Tsafar

I have a UILabeland in some cases the text is longer then the UILabelitself, so I see the text as "bla bla bla..."I want to add a ...Read Morebutton text at the end of the UILabel..

我有一个UILabel,在某些情况下,文本比UILabel它本身长,所以我看到文本,因为"bla bla bla..."我想...Read MoreUILabel..的末尾添加一个按钮文本。

I've read some posts but they offer solutions that are not good to me, for example: to calculate how many characters will enter the UILabel, but with the font i'm using each character has a different width.

我读过一些帖子,但他们提供的解决方案对我来说并不好,例如:计算将输入多少个字符UILabel,但是我使用的字体每个字符都有不同的宽度。

How can I manage to do that?

我怎样才能做到这一点?

Thanks in advance!

提前致谢!

采纳答案by Yossi Tsafar

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

所以这就是我将Read More...按钮添加到UITextView,UITextFieldUILabel

- (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:intoLabelmethod which can be found here.

有一种使用fitString:intoLabel方法可以在这里找到。

As for the UITagTapGestureRecognizeris just a normal UITapGestureRecognizersubclass with a NSIntegerproperty 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.

至于UITagTapGestureRecognizer只是一个普通的UITapGestureRecognizer子类,带有一个NSInteger名为 tag的属性。我这样做是因为我想确定哪些Read More...被点击,如果我有多个相同的UIViewController. 您可以使用正常的UITapGestureRecognizer.

Enjoy!

享受!

回答by ramchandra n

Swift4 (IOS 11.2)

Swift4 (IOS 11.2)

Readmoreat the end of the label without action

Readmore在标签中没有行动结束

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

斯威夫特 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.blue
DispatchQueue.main.async {
    self.yourLabel.addTrailing(with: "... ", moreText: "Readmore", moreTextFont: readmoreFont!, moreTextColor: readmoreFontColor)
}

Result

结果

Readmore label output

阅读更多标签输出

NOTE: - Action is not included for Readmore

注意: - Readmore 不包括操作

回答by Avner Barr

Tttattributed label has this feature

ttattributed 标签有这个功能

https://github.com/TTTAttributedLabel/TTTAttributedLabel

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

回答by Lance Samaria

This works for Swift 4.2

这适用于 Swift 4.2

Here is a safer version of @ramchandran's answer because you don't know how many characters the user will enter.

这是@ramchandran 答案的更安全版本,因为您不知道用户将输入多少个字符。

In his answer if the length of the string the user entered is less then the length of the whatever text you decide to use for ... Readmorethen it will crash. For eg this is how you use it

在他的回答中,如果用户输入的字符串长度小于您决定使用的任何文本的长度,... Readmore那么它将崩溃。例如,这就是您使用它的方式

if yourLabel.text!.count > 1 {

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

In the above example the output of ... Readmoreis 12 characters total. If the string the user entered was yourLabel.text = "12345678"then the string's text would only be 8 characters. It would crash because the range using ((trimmedString?.count ?? 0) - readMoreLength)in the line below would produce a negative result:

在上面的例子中,输出... Readmore总共是 12 个字符。如果用户输入的是字符串,yourLabel.text = "12345678"则字符串的文本将只有 8 个字符。它会崩溃,因为在((trimmedString?.count ?? 0) - readMoreLength)下面的行中使用的范围会产生负面结果:

// “12345678” minus “... Readmore” = negative four (8 - 12 = -4)
let trimmedForReadMore: String = (trimmedString! as NSString).replacingCharacters(in: NSRange(location: ((trimmedString?.count ?? 0) - readMoreLength), length: readMoreLength), with: "") + trailingText

I added a safety check to make sure that if the string entered is less then or equal to the number of characters for whatever you decide to use as ... Readmoreit will return and the line that will cause the crash will never get reached:

我添加了一个安全检查,以确保输入的字符串小于或等于您决定使用的任何字符数,因为... Readmore它将返回并且永远不会到达导致崩溃的行:

// trimmedString is the string the user entered
guard let safeTrimmedString = trimmedString else { return }
if safeTrimmedString.count <= readMoreLength { return }

It's located in the center of the addTrailingfunction

它位于addTrailing函数的中心

extension UILabel{    

    func addTrailing(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor) {

        let readMoreText: String = trailingText + moreText

        if self.visibleTextLength == 0 { return }

        let lengthForVisibleString: Int = self.visibleTextLength

        if let myText = self.text {

            let mutableString: String = myText

            let trimmedString: String? = (mutableString as NSString).replacingCharacters(in: NSRange(location: lengthForVisibleString, length: myText.count - lengthForVisibleString), with: "")

            let readMoreLength: Int = (readMoreText.count)

            guard let safeTrimmedString = trimmedString else { return }

            if safeTrimmedString.count <= readMoreLength { return }

            print("this number \(safeTrimmedString.count) should never be less\n")
            print("then this number \(readMoreLength)")

            // "safeTrimmedString.count - readMoreLength" should never be less then the readMoreLength because it'll be a negative value and will crash
            let trimmedForReadMore: String = (safeTrimmedString as NSString).replacingCharacters(in: NSRange(location: safeTrimmedString.count - 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 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)

        if let myText = self.text {

            let attributes: [AnyHashable: Any] = [NSAttributedString.Key.font: font]
            let attributedText = NSAttributedString(string: myText, 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 = (myText as NSString).rangeOfCharacter(from: characterSet, options: [], range: NSRange(location: index + 1, length: myText.count - index - 1)).location
                    }
                } while index != NSNotFound && index < myText.count && (myText as NSString).substring(to: index).boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, attributes: attributes as? [NSAttributedString.Key : Any], context: nil).size.height <= labelHeight
                return prev
            }
        }

        if self.text == nil {
            return 0
        } else {
            return self.text!.count
        }
    }
}

回答by Gurjinder Singh

Swift 4 and Swift 5. I need to implement the same. As answers are already given but according to me TTTAttributedLabel is the best way to do it. It gives you better control over content. Easy to find address, link, date etc. You can also change the color of links. TTTAttributedLabel Library link is already given in above answer. Lets come to implementation.

斯威夫特 4 和斯威夫特 5。我需要实现相同的。由于已经给出了答案,但据我所知 TTTAttributedLabel 是最好的方法。它使您可以更好地控制内容。易于查找地址、链接、日期等。您还可以更改链接的颜色。上面的答案中已经给出了 TTTAttributedLabel 库链接。让我们来实施。

let kCharacterBeforReadMore =  20
let kReadMoreText           =  "...ReadMore"
let kReadLessText           =  "...ReadLess"

@IBOutlet weak var labelText: TTTAttributedLabel! // setYouLabel Class to TTTAttributedLabel in StoryBoard
var strFull = ""

 override func viewDidLoad() {
      super.viewDidLoad()
      strFull = "I need to implement the same. As answers are already given but according to me TTTAttributedLabel is the best way to do it. I gives I need to implement the same. As answers are already given but according to me TTTAttributedLabel is the best way to do it. I gives you"
      labelText.showTextOnTTTAttributeLable(str: strFull, readMoreText: kReadMoreText, readLessText: kReadLessText, font: UIFont.init(name: "Helvetica-Bold", size: 24.0)!, charatersBeforeReadMore: kCharacterBeforReadMore, activeLinkColor: UIColor.blue, isReadMoreTapped: false, isReadLessTapped: false)
      labelText.delegate = self
   }
      func readMore(readMore: Bool) {
        labelText.showTextOnTTTAttributeLable(str: strFull, readMoreText: kReadMoreText, readLessText: kReadLessText, font: nil, charatersBeforeReadMore: kCharacterBeforReadMore, activeLinkColor: UIColor.blue, isReadMoreTapped: readMore, isReadLessTapped: false)
      }
      func readLess(readLess: Bool) {
        labelText.showTextOnTTTAttributeLable(str: strFull, readMoreText: kReadMoreText, readLessText: kReadLessText, font: nil, charatersBeforeReadMore: kCharacterBeforReadMore, activeLinkColor: UIColor.blue, isReadMoreTapped: readLess, isReadLessTapped: true)
      }
}

Here I have crated an extension of TTTAttributedLabel and put the ReadMore and ReadLess logic here. You can modify according to your.

在这里,我创建了 TTTAttributedLabel 的扩展,并将 ReadMore 和 ReadLess 逻辑放在这里。可以根据你的修改。

 extension TTTAttributedLabel {
      func showTextOnTTTAttributeLable(str: String, readMoreText: String, readLessText: String, font: UIFont?, charatersBeforeReadMore: Int, activeLinkColor: UIColor, isReadMoreTapped: Bool, isReadLessTapped: Bool) {

        let text = str + readLessText
        let attributedFullText = NSMutableAttributedString.init(string: text)
        let rangeLess = NSString(string: text).range(of: readLessText, options: String.CompareOptions.caseInsensitive)
//Swift 5
       // attributedFullText.addAttributes([NSAttributedStringKey.foregroundColor : UIColor.blue], range: rangeLess)
        attributedFullText.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.blue], range: rangeLess)

        var subStringWithReadMore = ""
        if text.count > charatersBeforeReadMore {
          let start = String.Index(encodedOffset: 0)
          let end = String.Index(encodedOffset: charatersBeforeReadMore)
          subStringWithReadMore = String(text[start..<end]) + readMoreText
        }

        let attributedLessText = NSMutableAttributedString.init(string: subStringWithReadMore)
        let nsRange = NSString(string: subStringWithReadMore).range(of: readMoreText, options: String.CompareOptions.caseInsensitive)
        //Swift 5
       // attributedLessText.addAttributes([NSAttributedStringKey.foregroundColor : UIColor.blue], range: nsRange)
        attributedLessText.addAttributes([NSAttributedString.Key.foregroundColor : UIColor.blue], range: nsRange)
      //  if let _ = font {// set font to attributes
      //   self.font = font
      //  }
        self.attributedText = attributedLessText
        self.activeLinkAttributes = [NSAttributedString.Key.foregroundColor : UIColor.blue]
        //Swift 5
       // self.linkAttributes = [NSAttributedStringKey.foregroundColor : UIColor.blue]
        self.linkAttributes = [NSAttributedString.Key.foregroundColor : UIColor.blue]
        self.addLink(toTransitInformation: ["ReadMore":"1"], with: nsRange)

        if isReadMoreTapped {
          self.numberOfLines = 0
          self.attributedText = attributedFullText
          self.addLink(toTransitInformation: ["ReadLess": "1"], with: rangeLess)
        }
        if isReadLessTapped {
          self.numberOfLines = 3
          self.attributedText = attributedLessText
        }
      }
    }

You need to implement the didSelectLinkWithTransitInformation delegate of TTTAttributedLabel. Here you can get the component which you have passed

您需要实现 TTTAttributedLabel 的 didSelectLinkWithTransitInformation 委托。在这里你可以得到你通过的组件

extension ViewController: TTTAttributedLabelDelegate {
  func attributedLabel(_ label: TTTAttributedLabel!, didSelectLinkWithTransitInformation components: [AnyHashable : Any]!) {
    if let _ = components as? [String: String] {
      if let value = components["ReadMore"] as? String, value == "1" {
        self.readMore(readMore: true)
      }
      if let value = components["ReadLess"] as? String, value == "1" {
        self.readLess(readLess: true)
      }
    }
  }
}

Result- Before tapping ReadMore

结果-点击之前阅读更多

enter image description here

在此处输入图片说明

Result- After tapping ReadMore

结果 - 点击后阅读更多

enter image description here

在此处输入图片说明

回答by Phan Van Linh

My solution is, I create a UIButton(name Read more) at bottom-right and below the UILabel. After that I check the UILabelis truncated or not for showing or hiding the UIButton

我的解决方案是,我UIButton在右下角和UILabel. 之后,我检查是否UILabel被截断以显示或隐藏UIButton

CGSize sizeOfText = [self.label.text boundingRectWithSize: CGSizeMake(self.label.intrinsicContentSize.width, CGFLOAT_MAX)
                                                 options: (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                              attributes: [NSDictionary dictionaryWithObject:self.label.font forKey:NSFontAttributeName] context: nil].size;

if (self.label.intrinsicContentSize.height < ceilf(sizeOfText.height)) {
    // label is truncated
    self.readmoreButton.hidden = NO; // show Read more button
}else{
    self.readmoreButton.hidden = YES;
}

=== Swift 3 version

=== Swift 3 版本

let textheight = self.label.text?.height(withConstrainedWidth: self.label.frame.width, font: self.label.font)
    if self.label.intrinsicContentSize.height < textheight! {
        self.readmoreButton.isHidden = false
    }else{
        self.readmoreButton.isHidden = true
    }

add this extension:

添加此扩展名:

extension String {

func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
    let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
    let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

    return boundingBox.height
}

}

}

Hope this help

希望这有帮助

回答by Phillip

You can try the 3rd library ExpandableLable

你可以试试第三个库ExpandableLable

Set the custom class of your UILabel to ExpandableLabel and set the desired number of lines and collapsed text:

将 UILabel 的自定义类设置为 ExpandableLabel 并设置所需的行数和折叠文本:

expandableLabel.numberOfLines = 5
expandableLabel.collapsedAttributedLink = NSAttributedString(string: "more")
expandableLabel.ellipsis = NSAttributedString(string: "...")
// update label expand or collapse state
expandableLabel.collapsed = true

You may need set a delegateto get notified in case the link has been touched.

您可能需要设置 adelegate以在链接被触摸的情况下收到通知。

回答by Dang Duy Nam

class DynamicLabel: UILabel{

    var fullText: String?
    var truncatedLength = 100
    var isTruncated = true

    func collapse(){
        let index = fullText!.index(fullText!.startIndex, offsetBy: truncatedLength)
        self.text = fullText![...index].description + "... More"
        isTruncated = true
    }

    func expand(){
        self.text = fullText
        isTruncated = false
    }

}

Just a simple trick to get through all these messy implementations. The idea is simple, we don't set collapsed or expand rows, just set the label to 0. Then store the original text on fullTextvariable. Now if we want to display collapsed format, then just get substring and add the custom ellipsis.

只是一个简单的技巧来完成所有这些凌乱的实现。这个想法很简单,我们不设置折叠或展开行,只需将标签设置为 0。然后将原始文本存储在fullText变量中。现在如果我们想显示折叠格式,那么只需获取子字符串并添加自定义省略号。

Note: This does not include tap event handlers, you can add it yourself on the controller.

注意:这不包括点击事件处理程序,您可以自己在控制器上添加它。

回答by Ctan Li

For Action on the label, if using a CollectionView or TableView you could use a delegate method to perform the action.

对于标签上的操作,如果使用 CollectionView 或 TableView,您可以使用委托方法来执行操作。

func showMore(cell: CustomCell) {
    guard let indexPath = self.tableView.indexPath(for: cell) else {
        return
    }
    let cell = tableView.cellForRow(at: indexPath) as! CustomCell
    tableView.beginUpdates()
    cell.label.text = "your complete text"
    tableView.endUpdates()
}

This updates the label and displays the full text as required Using Lance Samaria answer and adding the action for the cell.

这将更新标签并根据需要显示全文 使用 Lance Samaria 答案并为单元格添加操作。

回答by hris.to

Using method - boundingRectWithSize:options:attributes:context:and passing your font as NSFontAttributeNamekey for NSAttributedStringwill give you the correct rect needed.

使用方法- boundingRectWithSize:options:attributes:context:并将您的字体作为NSFontAttributeName键传递NSAttributedString给您所需的正确矩形。

From that you need to check if it's bigger than your label bounds minus offset. Only if yes, you need to trim your text and show Read Moreat the end.

从中您需要检查它是否大于标签边界减去偏移量。只有在是的情况下,您才需要修剪文本并Read More在最后显示。