it-swarm.com.ru

Добавьте "... Подробнее" в конец UILabel

У меня есть UILabel, а в некоторых случаях текст длиннее самого UILabel, поэтому я вижу текст как "bla bla bla...". Я хочу добавить текст кнопки ...Read More в конце UILabel ..

Я читал некоторые посты, но они предлагают решения, которые мне не подходят, например: подсчитать, сколько символов будет входить в UILabel, но с использованием шрифта, который я использую, каждый символ имеет разную ширину.

Как мне это сделать?

Заранее спасибо!

9
Yossi Tsafar

Вот что я сделал, чтобы добавить кнопку Read More ... к UITextView, UITextField или 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'...");

    }
}

Существует использование метода fitString:intoLabel, который можно найти здесь .

Что касается UITagTapGestureRecognizer, это просто обычный подкласс UITapGestureRecognizer со свойством NSInteger, называемым tag. Я сделал это, потому что я хочу определить, какой Read More... был нажат в том случае, если у меня более одного в той же UIViewController. Вы можете использовать обычный UITapGestureRecognizer.

Наслаждайтесь!

9
Yossi Tsafar

Swift4 (IOS 11.2)

Readmore в конце метки без действий

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: [NSAttributedStringKey.font: self.font])
        let readMoreAttributed = NSMutableAttributedString(string: moreText, attributes: [NSAttributedStringKey.font: moreTextFont, NSAttributedStringKey.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] = [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
        }
    }

Использование

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)
}

Результат

 Readmore label output

ПРИМЕЧАНИЕ: - Действие не включено для Readmore

18
ramchandra n

Tttattributed label имеет эту функцию

https://github.com/TTTAttributedLabel/TTTAttributedLabel

Вам нужно установить токен усечения как "Читать дальше ..." 

Увидеть

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
6
Avner Barr

Мое решение заключается в том, что я создаю UIButton (имя Read more) в правом нижнем углу и ниже 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 версия

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
    }

добавьте это расширение:

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
}

}

Надеюсь это поможет

2
Linh

Вы можете попробовать 3-ю библиотеку ExpandableLable

Установите пользовательский класс вашей UILabel на ExpandableLabel и установите желаемое количество строк и свернутый текст:

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

Вам может потребоваться установить delegate, чтобы получать уведомления в случае касания ссылки.

2
Phillip

Использование метода - boundingRectWithSize: options: attribute: context: и передача вашего шрифта в качестве ключа NSFontAttributeName для NSAttributedString даст вам правильный нужный прямоугольник.

Исходя из этого, вам нужно проверить, больше ли это, чем границы вашей этикетки минус смещение. Только если да, вам нужно обрезать текст и показать Read More в конце.

0
hris.to

этот метод полезен для showless и showAll с обновленным изображением стрелки: добавить наклейку на ярлык

  viewcontroller.h

  @property (nonatomic,assign) BOOL isReadable; 

  viewcontrollr.m

  #pragma mark :- Tap Gesture View All
  -(void)readMoreDidClickedGesture :(UITapGestureRecognizer 
    *)objTapGesture{

     UILabel * lblDesc = (UILabel *)[objTapGesture view];
     NSLog(@"%@",lblDesc.text);
     if (self.isReadable == false) {
     [self setIsReadable:YES];
     lblDesc.text = readmoreText;
     readMoreHeight = [self getLabelHeight:lblDesc];
     }
     else{
      readMoreHeight = 30.0;
      [self setIsReadable:NO];
      }  
  }



 - (void)addReadMoreStringToUILabel:(UILabel*)label isReaded:(BOOL)isReaded
 {

  NSString *readMoreText = (isReaded == false) ? @"...Show All  " : 
   @"Show Less  ";
  NSInteger lengthForString = label.text.length;
  if (lengthForString >= 30)
  {
    NSInteger lengthForVisibleString = [self getLabelHeight:label];//[self fitString:label.text intoLabel:label];
    NSMutableString *mutableString = [[NSMutableString alloc] initWithString:label.text];
    readmoreText = mutableString;
    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 :label.font,                              NSForegroundColorAttributeName :[UIColor orangeColor]
                                                                                                                                }];
    if (isReaded == false){
        [readMoreAttributed addAttribute:NSUnderlineStyleAttributeName
                             value:@(NSUnderlineStyleSingle)
                             range:NSMakeRange(3, 8)];

        NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
        UIImageView *imgDown = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 25, 25)];
        imgDown.image = [UIImage imageNamed:@"searchFilterArrow1"];
        imgDown.image = [imgDown.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        [imgDown setTintColor:[UIColor orangeColor]];

        textAttachment.image = imgDown.image;

        NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];

        [readMoreAttributed replaceCharactersInRange:NSMakeRange(12, 1) withAttributedString:attrStringWithImage];
    }
    else{
        [readMoreAttributed addAttribute:NSUnderlineStyleAttributeName
                                   value:@(NSUnderlineStyleSingle)
                                   range:NSMakeRange(1, 9)];
        NSTextAttachment *textAttachment = [[NSTextAttachment alloc] init];
        UIImageView *imgup = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 25, 25)];
        imgup.image = [UIImage imageNamed:@"searchFilterArrow2"];
        imgup.image = [imgup.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        [imgup setTintColor:[UIColor orangeColor]];

        textAttachment.image = imgup.image;

        NSAttributedString *attrStringWithImage = [NSAttributedString attributedStringWithAttachment:textAttachment];

        [readMoreAttributed replaceCharactersInRange:NSMakeRange(11, 1) withAttributedString:attrStringWithImage];
    }

    [answerAttributed appendAttributedString:readMoreAttributed];
    label.attributedText = answerAttributed;

    UITapGestureRecognizer *readMoreGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(readMoreDidClickedGesture:)];
    readMoreGesture.numberOfTapsRequired = 1;
    [label addGestureRecognizer:readMoreGesture];

    label.userInteractionEnabled = YES;
}
else {

    NSLog(@"No need for 'Read More'...");

}
}
0
Maulik Patel

Знаете ли вы, что UILabel не использует сенсорное действие? так что вы не можете коснуться «... Подробнее», если весь текст в UILabel.

Примечание: мое решение заключается в том, чтобы добавить кнопку UILabel с чистым фоном.

0
Jamil

Для действий  

 let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapFunction))
 Urlabel.isUserInteractionEnabled = true
 Urlabel.addGestureRecognizer(tap)

 @objc
    func tapFunction(sender:UITapGestureRecognizer) {


    }
0
Red Heart
func updateData(_ label: UILabel) {
    self.headerLabel.text = detailViewModel.firstTitle
    self.detailLabel.text = detailViewModel.firstContent

    headerTitle = detailViewModel.firstTitle
    detailTitle = detailViewModel.firstContent

    DispatchQueue.main.async {
        let readMoreText = "...View More"
        let stringColor: UIColor = UIColor.blue
        let attributes = [NSForegroundColorAttributeName: stringColor]

        let numberOfLines = self.detailLabel.numberOfVisibleLines

        if numberOfLines > 2 {

            let lengthForVisibleString: Int = self.fit( self.detailLabel.text, into: self.detailLabel)
            let mutableString = self.detailLabel.text ?? ""
            let trimmedString = (mutableString as NSString).replacingCharacters(in: NSRange(location: lengthForVisibleString, length: (self.detailLabel?.text?.count ?? 0) - lengthForVisibleString), with: "")
            let readMoreLength: Int = readMoreText.count
            let trimmedForReadMore = (trimmedString as NSString).replacingCharacters(in: NSRange(location: trimmedString.count - readMoreLength, length: readMoreLength), with: "")
            let answerAttributed = NSMutableAttributedString(string: trimmedForReadMore, attributes: [NSFontAttributeName: self.detailLabel.font])

            let readMoreAttributed = NSMutableAttributedString(string: readMoreText, attributes: attributes)
            answerAttributed.append(readMoreAttributed)
            self.detailLabel.attributedText = answerAttributed


            let readMoreGesture = UITapGestureRecognizer(target: self, action:#selector(FundDetailsTableViewCell.showViewMore(_:)))
            readMoreGesture.numberOfTapsRequired = 1
            self.detailLabel.addGestureRecognizer(readMoreGesture)
            self.detailLabel.isUserInteractionEnabled = true
        }
    }
}

func fit(_ string: String?, into label: UILabel?) -> Int {
    guard let stringObjc = string as NSString? else {
        return 0
    }
    let font: UIFont = label?.font ?? UIFont.systemFont(ofSize: 14.0)
    let mode: NSLineBreakMode? = label?.lineBreakMode
    let labelWidth: CGFloat? = label?.frame.size.width
    let labelHeight: CGFloat? = label?.frame.size.height
    let sizeConstraint = CGSize(width: labelWidth ?? 0.0, height: CGFloat.greatestFiniteMagnitude)
    let attributes = [NSFontAttributeName: font]

    let device = UIDevice.current
    let iosVersion = Double(device.systemVersion) ?? 0

    if iosVersion > 7 {
        let attributedText = NSAttributedString(string: string ?? "", attributes: attributes)
        let boundingRect: CGRect = attributedText.boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, context: nil)
        do {
            if boundingRect.size.height > (labelHeight ?? 0.0) {
                var index: Int = 0
                var prev: Int
                let characterSet = CharacterSet.whitespacesAndNewlines
                repeat {
                    prev = index
                    if mode == .byCharWrapping {
                        index += 1
                    } else {
                        index = Int((string as NSString?)?.rangeOfCharacter(from: characterSet, options: [], range: NSRange(location: index + 1, length: (string?.count ?? 0) - index - 1)).location ?? 0)
                    }
                } while index != NSNotFound && index < (string?.count ?? 0)
                    && (stringObjc.substring(to: index).boundingRect(with: sizeConstraint, options: .usesLineFragmentOrigin, attributes: attributes, context: nil).size.height) <= labelHeight!
                return prev;
            }
        }
    } else {
        if stringObjc.size(attributes: attributes).height > labelHeight! {
            var index: Int = 0
            var prev: Int
            let characterSet = CharacterSet.whitespacesAndNewlines
            repeat {
                prev = index
                if mode == .byCharWrapping {
                    index += 1
                } else {
                    index = stringObjc.rangeOfCharacter(from: characterSet, options: NSString.CompareOptions.caseInsensitive, range: NSRange(location: index + 1, length: stringObjc.length - index - 1)).location
                }

            } while index != NSNotFound && index < (string?.count)! && (stringObjc.substring(to: index) as NSString).size(attributes: attributes).height <= labelHeight!
            return prev

        }
    }
    return (string?.count)!
}

func showViewMore(_ sender: UITapGestureRecognizer) {

}

extension UILabel {
    var numberOfVisibleLines: Int {
        let textSize = CGSize(width: CGFloat(self.frame.size.width), height: CGFloat(MAXFLOAT))
        let rHeight: Int = lroundf(Float(self.sizeThatFits(textSize).height))
        let charSize: Int = lroundf(Float(self.font.pointSize))
        return rHeight / charSize
    }
}
0
Ashok Mango