我有UILabel
,在某些情况下,文字比UILabel
本身长,所以我看到文字为"bla bla bla..."
我要添加...Read More
按钮UILabel
..
我已经阅读了一些帖子,但是他们提供了对我不好的解决方案,例如:计算将有多少字符进入UILabel
,但是使用我使用的字体每个字符都有不同的字符宽度。
我怎样设法做到这一点?
提前致谢!
答案 0 :(得分:18)
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.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
}
}
<强> 用法 强>
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不包含操作
答案 1 :(得分:9)
所以我这样做是为了向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
方法可以找到here。
至于UITagTapGestureRecognizer
只是一个普通的UITapGestureRecognizer
子类,其NSInteger
属性称为tag。我这样做是因为我想确定哪个Read More...
被点击了我的情况我在同一个UIViewController
中有多个UITapGestureRecognizer
。您可以使用普通setAdapter
。
享受!
答案 2 :(得分:7)
Tttattributed标签具有此功能
https://github.com/TTTAttributedLabel/TTTAttributedLabel
你需要设置&#34;截断&#34;令牌为 &#34;阅读更多......&#34;
见
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
答案 3 :(得分:2)
我的解决方案是,我在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版
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
}
}
希望这个帮助
答案 4 :(得分:2)
您可以尝试第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
以便在触摸链接时收到通知。
答案 5 :(得分:0)
使用方法- boundingRectWithSize:options:attributes:context:并将字体作为NSFontAttributeName
的{{1}}键传递,将为您提供所需的正确矩形。
由此您需要检查它是否大于您的标签边界减去偏移量。只有在是的情况下,您需要修剪文本并在结尾处显示NSAttributedString
。
答案 6 :(得分:0)
此方法对于showless和showAll以及向上箭头图像非常有用: 在标签上添加tapgesture
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'...");
}
}
答案 7 :(得分:0)
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
}
}
答案 8 :(得分:0)
采取行动
let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapFunction))
Urlabel.isUserInteractionEnabled = true
Urlabel.addGestureRecognizer(tap)
@objc
func tapFunction(sender:UITapGestureRecognizer) {
}
答案 9 :(得分:0)
这适用于Swift 4.2
这是@ramchandran答案的更安全版本。
在他的答案中,如果字符串的长度小于您决定用于的任何文本的长度... 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)
}
}
在上面的示例中,... Readmore
的输出总共为12个字符。如果您的字符串是yourLabel.text = "12345678"
,则字符串的文本只能是8个字符。
它将崩溃,因为在下面一行中使用((trimmedString?.count ?? 0) - readMoreLength)
的范围将产生负结果:
let trimmedForReadMore: String = (trimmedString! as NSString).replacingCharacters(in: NSRange(location: ((trimmedString?.count ?? 0) - readMoreLength), length: readMoreLength), with: "") + trailingText
我添加了安全检查,以确保字符串小于您打算用作readmore的字符数
guard let safeTrimmedString = trimmedString else { return }
if safeTrimmedString.count <= readMoreLength { return }
它位于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
}
}
}
答案 10 :(得分:0)
Swift 4和Swift 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)
}
}
在这里,我创建了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 {
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
}
}
}
您需要实现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)
}
}
}
}
结果-在点击ReadMore
之前结果-点击ReadMore
后答案 11 :(得分:0)
对于标签上的操作,如果使用CollectionView或TableView,则可以使用委托方法执行操作。
public class Hourglass {
public static void main(String[] args) {
hourglass(Integer.parseInt(args[0]), 0);
}
private static void hourglass(int size, int offset) {
// print top line
printHourglassLine(size, offset);
if (size > 1) {
// recursive call
hourglass(size - 1, offset + 1);
// print bottom line
printHourglassLine(size, offset);
}
}
private static void printHourglassLine(int size, int offset) {
System.out.println(" ".repeat(offset) + "* ".repeat(size));
}
}
这将更新标签并根据需要显示全文 使用Lance Samaria回答并为该单元添加操作。
答案 12 :(得分:0)
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
}
}
这是完成所有这些混乱实现的简单技巧。这个想法很简单,我们不设置折叠或展开行,只需将标签设置为0。
然后将原始文本存储在fullText
变量中。现在,如果要显示折叠格式,则只需获取子字符串并添加自定义省略号即可。
注意:这不包括点击事件处理程序,您可以将其自己添加到控制器上。
答案 13 :(得分:0)
TTTAttributedLabel:-使用以下代码行设置字体
attributedLessText = NSMutableAttributedString(字符串:subStringWithReadMore,属性:[NSAttributedString.Key.font:UIFont.systemFont(ofSize:17)])
答案 14 :(得分:0)
这是Swift 5的另一个解决方案。
逻辑很简单。
... more
替换子字符串(可以更改)private func getIndex(from point: CGPoint) -> Int?
func didTapInRange(_ point: CGPoint, targetRange: NSRange) -> Bool
let loremIpsumString = """
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
"""
private var expandableTextRange: NSRange?
//...in ViewDidLoad
label.text = loremIpsumString
if label.isTruncatedText {
expandableTextRange = label.setExpandActionIfPossible("More", textColor: .brown)
}
//Add IBAction on the label
@IBAction func didTapLabel(_ sender: UITapGestureRecognizer) {
guard let expandRange = expandableTextRange else {
return
}
let tapLocation = sender.location(in: label)
if label.didTapInRange(tapLocation, targetRange: expandRange) {
label.numberOfLines = 0
label.text = loremIpsumString
}
else {
resultLabel.text = "You tapped the area outside More."
}
}
extension UILabel {
var isTruncatedText: Bool {
guard let height = textHeight else {
return false
}
return height > bounds.size.height
}
var textHeight: CGFloat? {
guard let labelText = text else {
return nil
}
let attributes: [NSAttributedString.Key: UIFont] = [.font: font]
let labelTextSize = (labelText as NSString).boundingRect(
with: CGSize(width: frame.size.width, height: .greatestFiniteMagnitude),
options: .usesLineFragmentOrigin,
attributes: attributes,
context: nil
).size
return ceil(labelTextSize.height)
}
@discardableResult
func setExpandActionIfPossible(_ text: String, textColor: UIColor? = nil) -> NSRange? {
guard isTruncatedText, let visibleString = visibleText else {
return nil
}
let defaultTruncatedString = "... "
let fontAttribute: [NSAttributedString.Key: UIFont] = [.font: font]
let expandAttributedString: NSMutableAttributedString = NSMutableAttributedString(
string: defaultTruncatedString,
attributes: fontAttribute
)
let customExpandAttributes: [NSAttributedString.Key: Any] = [
.font: font as Any,
.foregroundColor: (textColor ?? self.textColor) as Any
]
let customExpandAttributedString = NSAttributedString(string: "\(text)", attributes: customExpandAttributes)
expandAttributedString.append(customExpandAttributedString)
let visibleAttributedString = NSMutableAttributedString(string: visibleString, attributes: fontAttribute)
guard visibleAttributedString.length > expandAttributedString.length else {
return nil
}
let changeRange = NSRange(location: visibleAttributedString.length - expandAttributedString.length, length: expandAttributedString.length)
visibleAttributedString.replaceCharacters(in: changeRange, with: expandAttributedString)
attributedText = visibleAttributedString
return changeRange
}
var visibleText: String? {
guard isTruncatedText,
let labelText = text,
let lastIndex = truncationIndex else {
return nil
}
let visibleTextRange = NSRange(location: 0, length: lastIndex)
guard let range = Range(visibleTextRange, in: labelText) else {
return nil
}
return String(labelText[range])
}
//https://stackoverflow.com/questions/41628215/uitextview-find-location-of-ellipsis-in-truncated-text/63797174#63797174
var truncationIndex: Int? {
guard let text = text, isTruncatedText else {
return nil
}
let attributes: [NSAttributedString.Key: UIFont] = [.font: font]
let attributedString = NSAttributedString(string: text, attributes: attributes)
let textContainer = NSTextContainer(
size: CGSize(width: frame.size.width,
height: CGFloat.greatestFiniteMagnitude)
)
textContainer.maximumNumberOfLines = numberOfLines
textContainer.lineBreakMode = lineBreakMode
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(textContainer)
let textStorage = NSTextStorage(attributedString: attributedString)
textStorage.addLayoutManager(layoutManager)
//Determine the range of all Glpyhs within the string
var glyphRange = NSRange()
layoutManager.glyphRange(
forCharacterRange: NSMakeRange(0, attributedString.length),
actualCharacterRange: &glyphRange
)
var truncationIndex = NSNotFound
//Iterate over each 'line fragment' (each line as it's presented, according to your `textContainer.lineBreakMode`)
var i = 0
layoutManager.enumerateLineFragments(
forGlyphRange: glyphRange
) { rect, usedRect, textContainer, glyphRange, stop in
if (i == self.numberOfLines - 1) {
//We're now looking at the last visible line (the one at which text will be truncated)
let lineFragmentTruncatedGlyphIndex = glyphRange.location
if lineFragmentTruncatedGlyphIndex != NSNotFound {
truncationIndex = layoutManager.truncatedGlyphRange(inLineFragmentForGlyphAt: lineFragmentTruncatedGlyphIndex).location
}
stop.pointee = true
}
i += 1
}
return truncationIndex
}
//https://stackoverflow.com/questions/1256887/create-tap-able-links-in-the-nsattributedstring-of-a-uilabel
private func getIndex(from point: CGPoint) -> Int? {
guard let attributedString = attributedText, attributedString.length > 0 else {
return nil
}
let textStorage = NSTextStorage(attributedString: attributedString)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: frame.size)
textContainer.lineFragmentPadding = 0
textContainer.maximumNumberOfLines = numberOfLines
textContainer.lineBreakMode = lineBreakMode
layoutManager.addTextContainer(textContainer)
let index = layoutManager.characterIndex(
for: point,
in: textContainer,
fractionOfDistanceBetweenInsertionPoints: nil
)
return index
}
func didTapInRange(_ point: CGPoint, targetRange: NSRange) -> Bool {
guard let indexOfPoint = getIndex(from: point) else {
return false
}
return indexOfPoint > targetRange.location &&
indexOfPoint < targetRange.location + targetRange.length
}
}
答案 15 :(得分:-1)
你知道UILabel没有触摸动作吗?所以你不能触摸......阅读更多&#39;如果是UILabel中的全文。
注意:我的解决方案是,添加UILabel的清晰背景按钮。