Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在Swift中的UILabel末尾显示更多/显示更少_Ios_Swift_Uilabel - Fatal编程技术网

Ios 在Swift中的UILabel末尾显示更多/显示更少

Ios 在Swift中的UILabel末尾显示更多/显示更少,ios,swift,uilabel,Ios,Swift,Uilabel,我需要在像facebook这样的UILabel中实现show more/show less。我的标签具有提及和url功能。当文本中没有表情符号时,一切都很完美。我通过计算标签的文本高度和可见文本,在标签的末尾添加了尾随 这是我的扩展文件 // // extension.swift // SeeMore // // Created by Macbook Pro on 14/10/20. // import Foundation import UIKit //MARK : - text h

我需要在像facebook这样的UILabel中实现show more/show less。我的标签具有提及和url功能。当文本中没有表情符号时,一切都很完美。我通过计算标签的文本高度和可见文本,在标签的末尾添加了尾随

这是我的扩展文件

//
//  extension.swift
//  SeeMore
//
//  Created by Macbook Pro on 14/10/20.
//

import Foundation
import UIKit
//MARK : -  text height, weidth
extension Range where Bound == String.Index {
    var nsRange:NSRange {
        return NSRange(location: self.lowerBound.encodedOffset,
                       length: self.upperBound.encodedOffset -
                        self.lowerBound.encodedOffset)
    }
}
extension String {
    var extractURLs: [URL] {
        var urls : [URL] = []
        var error: NSError?
        let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
        
        var text = self
        
        detector!.enumerateMatches(in: text, options: [], range: NSMakeRange(0, text.count), using: { (result: NSTextCheckingResult!, flags: NSRegularExpression.MatchingFlags, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
            //            println("\(result)")
            print("Extracted Result: \(result.url)")
            urls.append(result.url!)
        })
        
        return urls
    }
    func textHeight(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: [NSAttributedString.Key.font: font], context: nil)
        
        return boundingBox.height
    }
    
    func textWidth(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        
        return boundingBox.width
    }
}


extension UILabel{
    
    func indexOfAttributedTextCharacterAtPoint(point: CGPoint, font : UIFont) -> Int {
        
        guard let attributedString = self.attributedText else { return -1 }
        
        let mutableAttribString = NSMutableAttributedString(attributedString: attributedString)
        // Add font so the correct range is returned for multi-line labels
        mutableAttribString.addAttributes([NSAttributedString.Key.font: font], range: NSRange(location: 0, length: attributedString.length))
        
        let textStorage = NSTextStorage(attributedString: mutableAttribString)
        
        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 addTrailingForShowLess(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor, complition: @escaping (_ attribute: NSMutableAttributedString) -> Void) {
        
        let readMoreText: String = trailingText + moreText
        
        
        if let myText = self.text {
            let trimmedString: String? = myText + trailingText
            
            let readMoreLength: Int = (readMoreText.count)
            
            guard let safeTrimmedString = trimmedString else { return }
            
            if safeTrimmedString.count <= readMoreLength { return }
            
            print("less this number \(safeTrimmedString.count) should never be less\n")
            print("less 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, length: readMoreLength), with: "") + trailingText
            
            let answerAttributed = NSMutableAttributedString(string: safeTrimmedString, attributes: [NSAttributedString.Key.font: moreTextFont])
            let readMoreAttributed = NSMutableAttributedString(string: moreText, attributes: [NSAttributedString.Key.font: moreTextFont, NSAttributedString.Key.foregroundColor: moreTextColor])
            answerAttributed.append(readMoreAttributed)
            complition(answerAttributed)
            //            self.attributedText = answerAttributed
        }
    }
    func addTrailing(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor, complition: @escaping (_ attribute: NSMutableAttributedString) -> Void) {
        
        let readMoreText: String = trailingText + moreText
        if self.text?.count == 0 { return }
        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 + 2)
            
            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: moreTextFont])
            let readMoreAttributed = NSMutableAttributedString(string: moreText, attributes: [NSAttributedString.Key.font: moreTextFont, NSAttributedString.Key.foregroundColor: moreTextColor])
            answerAttributed.append(readMoreAttributed)
            complition(answerAttributed)
            //            self.attributedText = answerAttributed
        }
    }
    
    var visibleTextLength: Int {
        
        let font: UIFont = self.font
        let mode: NSLineBreakMode = self.lineBreakMode
        let screenSize = UIScreen.main.bounds
        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
        }
    }
    
}
//
//斯威夫特分机
//希莫尔
//
//由Macbook Pro于20年10月14日创建。
//
进口基金会
导入UIKit
//标记:-文字高度,宽度
扩展范围,其中Bound==String.Index{
变量nsRange:nsRange{
返回NSRange(位置:self.lowerBound.encodedOffset,
长度:self.upperBound.encodedOffset-
self.lowerBound.encodedOffset)
}
}
扩展字符串{
var-extractURL:[URL]{
变量URL:[URL]=[]
var错误:N错误?
let detector=try?NSDataDetector(类型:NSTextCheckingResult.CheckingType.link.rawValue)
var text=self
detector!.enumerateMatches(in:text,options:[],range:NSMakeRange(0,text.count),使用:{(result:NSTextCheckingResult!,标志:NSRegularExpression.MatchingFlags,stop:UnsafeMutablePointer)->Void in
//println(“\(结果)”)
打印(“提取的结果:\(Result.url)”)
url.append(result.url!)
})
返回URL
}
func textHeight(withConstrainedWidth:CGFloat,font:UIFont)->CGFloat{
let constraintRect=CGSize(宽度:宽度,高度:.greatestfinitemagnity)
让boundingBox=self.boundingRect(带:constraintRect,选项:[.usesLineFragmentOrigin,.UseSFuntleding],属性:[NSAttribute String.Key.font:font],上下文:nil)
返回boundingBox.height
}
func textWidth(带约束高度高度:CGFloat,字体:UIFont)->CGFloat{
让constraintRect=CGSize(宽度:。最大有限大小,高度:高度)
让boundingBox=self.boundingRect(带:constraintRect,选项:.usesLineFragmentOrigin,属性:[NSAttributeString.Key.font:font],上下文:nil)
返回boundingBox.width
}
}
扩展UILabel{
func indexOfAttributedTextCharacterAtPoint(point:CGPoint,font:UIFont)->Int{
guard let attributedString=self.attributedText else{return-1}
让mutableAttribString=NSMutableAttributedString(attributedString:attributedString)
//添加字体,以便为多行标签返回正确的范围
mutableAttribString.addAttributes([NSAttributedString.Key.font:font],范围:NSRange(位置:0,长度:attributedString.length))
让textStorage=NSTextStorage(AttributeString:mutableAttribString)
让layoutManager=NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
让textContainer=NSTextContainer(大小:frame.size)
textContainer.lineFragmentPadding=0
textContainer.maximumNumberOfLines=numberOfLines
textContainer.lineBreakMode=lineBreakMode
layoutManager.addTextContainer(textContainer)
让index=layoutManager.characterIndex(for:point,in:textContainer,插入点之间距离的分数:nil)
回报指数
}
func addTrailingForShowLess(带有trailingText:String、moreText:String、moreTextFont:UIFont、moreTextColor:UIColor、complition:@escaping(uu属性:nsmutableAttributeString)->Void){
让readMoreText:String=trailingText+moreText
如果让myText=self.text{
让trimmedString:String?=myText+trailingText
让readMoreLength:Int=(readMoreText.count)
guard let safeTrimmedString=trimmedString else{return}
如果是safeTrimmedString.count labelHeight{
var指数:Int=0
var-prev:Int=0
让characterSet=characterSet.whitespaces和换行符
重复{
prev=指数
if mode==NSLineBreakMode.byCharWrapping{
指数+=1
}否则{
index=(myText作为NSString)。rangeOfCharacter(from:characterSet,options:[],range:NSRange(位置:index+1,长度:myText.count-index-1))。位置
}
}while index!=NSNotFound&&index
我希望它对你有用。

谢谢。

我以前用过它,有时它不起作用。更重要的是,我不能添加单点击手势(这是我访问上述用户配置文件和链接url时必须使用的手势)在上面。它只允许我使用长按手势。你能提供简单的代码来演示这个问题吗?你看过吗?有人发了帖子,看起来很像你在问什么。我不想使用任何库,因为大多数时候它们与一些要求相冲突。我也不是第三方LIB的粉丝……但你可以你能用一个简单的例子来编辑你的问题吗?如果我们不必花时间去弄清楚如何设置和重现你的问题,那么提供帮助就容易多了。谢谢你的回复。我已经编辑了我的帖子,请看一下。TIA。你必须创建一个xib文件来处理它。
 //
//  PostTableViewCell.swift
//  SeeMore
//
//  Created by Macbook Pro on 14/10/20.
//

import UIKit
protocol PostTableViewCellDelegate {
    func postLabelAction(cell: PostTableViewCell, post: Post, tap: UITapGestureRecognizer)
}

class PostTableViewCell: UITableViewCell {

    @IBOutlet weak var postLabel: UILabel!
    var currentPost : Post?
    var delegate: PostTableViewCellDelegate?
    override func awakeFromNib() {
        super.awakeFromNib()
        postLabel.textColor = .black
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(postLabelSelected))
        tapGesture.numberOfTapsRequired = 1
        postLabel.isUserInteractionEnabled = true
        postLabel.addGestureRecognizer(tapGesture)
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    @objc func postLabelSelected(tap: UITapGestureRecognizer) {
        delegate?.postLabelAction(cell: self, post: currentPost!, tap: tap)
    }
    
    func applyAttributedStringToPost(attributedString: NSMutableAttributedString, item: Post) {
        let text = attributedString.string
        let urls = text.extractURLs
        for url in urls {
            let range1 = (text as NSString).range(of: url.absoluteString)
            attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.blue, range: range1)
            postLabel.attributedText = attributedString
        }
        postLabel.attributedText = attributedString
    }
    
    func setupItems(item : Post){
        currentPost = item
        let postText = item.postText
        postLabel.numberOfLines = item.isExpendable ? 0 : 4
        postLabel.text = postText
        let underlineAttriString = NSMutableAttributedString(string: postText)
        let urls = postText.extractURLs
        for url in urls {
            let range1 = (postText as NSString).range(of: url.absoluteString)
            underlineAttriString.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.blue, range: range1)
            postLabel.attributedText = underlineAttriString
        }
        //Apply See more see less
        postLabel.sizeToFit()
//        let screenSize = UIScreen.main.bounds/
        if let newfont = postLabel.font {
            let textHeight = postText.textHeight(withConstrainedWidth: postLabel.frame.size.height, font: newfont)
            if item.isExpendable {
                postLabel.addTrailingForShowLess(with: "...", moreText: "Show Less", moreTextFont: newfont, moreTextColor: UIColor.blue) { (attributedString) in
                    self.applyAttributedStringToPost(attributedString: attributedString, item: item)
                }
            } else if postLabel.frame.size.height < textHeight, !item.isExpendable {
                postLabel.addTrailing(with: "...", moreText: "Show More", moreTextFont: newfont, moreTextColor: UIColor.blue) { (attributedString) in
                    self.applyAttributedStringToPost(attributedString: attributedString, item: item)
                }
            }
        }
    }
}