카테고리 없음

swift 라벨에 더보기 기능 넣어보자

kingarthur 2024. 9. 7. 11:36

일단 라벨에 더보기 기능을 넣고 싶었는데 

한참을 헤매다가 안되어서...포기하고 한숨자고 다시 도전 

열심히 구글링해보니 역시 해답은 여기!!!!

 

https://dy-yb.github.io/2022/UILabelSeeMore/

 

UILabel text에 더보기 붙이기

긴 글의 내용이 일정한 길이로 축약되어 나타나는 label 만들기

dy-yb.github.io

여기에서 참고해서 사용했다. 

 

    let memoLabel: UILabel = {
        let label = UILabel()
        label.text = """
        remember my workout
        asdfasdfasdfasdfasdfasdf
        asdfasdfasdf
        asdfasdfasdf
        asdfasdf
        """
        label.font = UIFont.systemFont(ofSize: 17, weight: .regular)
        label.textColor = .white
        label.numberOfLines = 3  // 세 줄까지만 표시
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    let seeMoreButton: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("더보기", for: .normal)
        button.setTitleColor(.gray, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .regular)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

 먼저 라벨하나 추가하고 버튼 하나를 추가해야된다 ~ 키특키득 

 

            memoLabel.topAnchor.constraint(equalTo: goalLable.bottomAnchor, constant: 0),
            memoLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
            memoLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
            
            seeMoreButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
            seeMoreButton.bottomAnchor.constraint(equalTo: memoLabel.bottomAnchor), // 같은 줄에 위치하도록
            
                    // 초기 '더보기' 버튼 상태 설정
        checkMemoLabel()
        
        // 버튼 클릭 시 호출될 메서드 설정
           seeMoreButton.addTarget(self, action: #selector(didTapSeeMore), for: .touchUpInside)

레이아웃은 나는 이렇게 잡았다.  

 

  // 메모라벨을 확인하고 더보기 기능 적용
    private func checkMemoLabel() {
        DispatchQueue.main.async {
            self.memoLabel.addTrailing(with: "... ", moreText: "more", moreTextFont: UIFont.systemFont(ofSize: 15), moreTextColor: UIColor.gray)
        }
    }
    
    // '더보기' 버튼 클릭 시 전체 텍스트 표시
    @objc private func didTapSeeMore() {
        if memoLabel.numberOfLines == 3 {
            memoLabel.numberOfLines = 0 // 전체 텍스트 표시
            seeMoreButton.setTitle("folding", for: .normal) // 버튼 제목을 "접기"로 변경
        } else {
            memoLabel.numberOfLines = 3 // 다시 3줄로 제한
            seeMoreButton.setTitle("more", for: .normal) // 버튼 제목을 "더보기"로 변경
        }
    }

요렇게 함수를 붙쳐주면 된다. 라인은 나는 3개까지만 보여주고 싶어서 그렇게 했는데 알아서 변경하면된다.

 

extension UILabel {
    func addTrailing(with trailingText: String, moreText: String, moreTextFont: UIFont, moreTextColor: UIColor) {
        let readMoreText = trailingText + moreText
        
        // Check if the text fits within the label
        guard let originalText = self.text, self.numberOfLines == 2 else { return }
        
        let visibleTextLength = self.visibleTextLength()
        let truncatedText = (originalText as NSString).replacingCharacters(in: NSRange(location: visibleTextLength, length: originalText.count - visibleTextLength), with: "")
        
        let attributedString = NSMutableAttributedString(string: truncatedText, attributes: [NSAttributedString.Key.font: self.font ?? UIFont.systemFont(ofSize: 17)])
        let readMoreAttributedString = NSMutableAttributedString(string: readMoreText, attributes: [NSAttributedString.Key.font: moreTextFont, NSAttributedString.Key.foregroundColor: moreTextColor])
        
        attributedString.append(readMoreAttributedString)
        self.attributedText = attributedString
    }
    
    func visibleTextLength() -> Int {
        guard let font = self.font else { return 0 }
        let mode = self.lineBreakMode
        let labelWidth = self.frame.size.width
        let labelHeight = self.font.lineHeight * CGFloat(self.numberOfLines)
        
        let size = CGSize(width: labelWidth, height: labelHeight)
        let attributes = [NSAttributedString.Key.font: font]
        let attributedText = NSAttributedString(string: self.text ?? "", attributes: attributes)
        let textStorage = NSTextStorage(attributedString: attributedText)
        let layoutManager = NSLayoutManager()
        let textContainer = NSTextContainer(size: size)
        textContainer.lineBreakMode = mode
        textContainer.maximumNumberOfLines = self.numberOfLines
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)
        
        let range = NSRange(location: 0, length: layoutManager.numberOfGlyphs)
        var index = 0
        layoutManager.enumerateLineFragments(forGlyphRange: range) { _, _, _, _, stop in
            if index >= self.numberOfLines {
                stop.pointee = true
            }
            index += 1
        }
        
        return layoutManager.characterRange(forGlyphRange: NSRange(location: 0, length: layoutManager.numberOfGlyphs), actualGlyphRange: nil).length
    }
}

마지막으로 익스텐션으로 라벨의 기능을 넣어주면 된다. 동적으로 움직이고 계산해주는 ~~~~ 

이렇게 하니 속 시원하게 잘 되네. 

다음에도 잘 이용해먹자 아자자!