apple/iOS, UIKit, Documentation

(iOS) TTGTagCollectionView 라이브러리 공부하기

lgvv 2022. 2. 17. 02:14

(iOS) TTGTagCollectionView 라이브러리 공부하기

 

최근에 태그와 관련한 UI를 구성하는 요구사항이 있었는데, 현직자분이 해당 라이브러리를 추천해주셔서 적용해보려고 한다.

UICollectionView로도 충분히 구현할 수 있지만, 현업에서는 오픈소스를 활용한다고 한다.

오픈소스를 코드를 읽고 분석하며 이를 프로젝트 형태에 맞게 적용하는 것 또한 중요하다고 해서 사용하면서 배워보고자 한다.


SPM을 공식적으로 지원하지 않아서 CocoaPod를 통해서 사용하는게 더 편하다.

SPM쓰려면 직접 Package를 배포해야하는데, 이 부분은 아직 잘 모르겠다.

 

 

오픈소스 링크

https://github.com/zekunyan/TTGTagCollectionView

 

GitHub - zekunyan/TTGTagCollectionView: Useful for showing text or custom view tags in a vertical or horizontal scrollable view

Useful for showing text or custom view tags in a vertical or horizontal scrollable view and support Autolayout at the same time. It is highly customizable that most features of the text tag can be ...

github.com

 

가능한 UI의 예제를 제안해주는데, 눈에 잘 보여서 좋다.

 

오픈소스 예제

 

 

내가 필요한 부분은 좌우로 쭉 늘어나는 태그인데, 아래처럼 구성해보았다.

 

내가 만든 태그 UI

 

코드는 생각보다 간편한데, 아래를 보자.

 

태그를 만드는 코드

//
//  NewsListTableViewHeaderView.swift
//  KeywordNews
//
//  Created by Hamlit Jason on 2022/02/05.
//

import UIKit

import SnapKit
import TTGTags

protocol NewsListTableViewHeaderViewDelegate: AnyObject {
    func didSelectTag(_ selectedIndex: Int)
}

final class NewsListTableViewHeaderView: UITableViewHeaderFooterView {
    static let identifier = "NewsListTableViewHeaderView"

    private lazy var tagCollectionView = TTGTextTagCollectionView()
    
    private weak var delegate: NewsListTableViewHeaderViewDelegate?
    
    private var tags: [String] = []

    
    func setup(
        tags: [String],
        delegate: NewsListTableViewHeaderViewDelegate
    ) {
        self.tags = tags
        self.delegate = delegate
        
        contentView.backgroundColor = .systemBackground
        
        setupTagCollectionViewLayout()
        setupTagCollectionView()
    }
}


extension NewsListTableViewHeaderView: TTGTextTagCollectionViewDelegate {
    func textTagCollectionView(_ textTagCollectionView: TTGTextTagCollectionView!, didTap tag: TTGTextTag!, at index: UInt) {
        print("textTagCollectionView \(tag)")
        guard tag.selected else { return } // 태그가 셀렉 되었을 때만 불려지게끔 필터링 해주기 -> 태그가 셀렉되지 않은 상태로 조건이 변경될 때도 불려지기 때문에
        
        delegate?.didSelectTag(Int(index))
    }
    
    func textTagCollectionView(_ textTagCollectionView: TTGTextTagCollectionView!, canTap tag: TTGTextTag!, at index: UInt) -> Bool {
        print("canTap")
        
        return true
    }
    
}

private extension NewsListTableViewHeaderView {
    func setupTagCollectionViewLayout() {
        addSubview(tagCollectionView)
        
        tagCollectionView.snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
    }
    
    func setupTagCollectionView() {
        tagCollectionView.delegate = self
        tagCollectionView.numberOfLines = 1
        tagCollectionView.scrollDirection = .horizontal
        tagCollectionView.showsVerticalScrollIndicator = false
        tagCollectionView.selectionLimit = 1
        
        let insetValue: CGFloat = 16.0
        tagCollectionView.contentInset = UIEdgeInsets(
            top: insetValue,
            left: insetValue,
            bottom: insetValue,
            right: insetValue
        )
        
        let cornerRadiusValue: CGFloat = 12.0
        let shadowOpacity: CGFloat = 0.0
        let extraSpace = CGSize(width: 20.0, height: 12.0)
        let color = UIColor.systemOrange
        
        let style = TTGTextTagStyle()
        style.backgroundColor = color
        style.cornerRadius = cornerRadiusValue
        style.borderWidth = 0.0
        style.shadowOpacity = shadowOpacity
        style.extraSpace = extraSpace

        let selectedStyle = TTGTextTagStyle()
        selectedStyle.backgroundColor = .white
        selectedStyle.cornerRadius = cornerRadiusValue
        selectedStyle.shadowOpacity = shadowOpacity
        selectedStyle.extraSpace = extraSpace
        selectedStyle.borderColor = color
        
        tags.forEach { tag in
            let font = UIFont.systemFont(ofSize: 14.0, weight: .semibold)
            let tagContents = TTGTextTagStringContent(
                text: tag,
                textFont: font,
                textColor: .white
            )
            let selectedTagContents = TTGTextTagStringContent(
                text: tag,
                textFont: font,
                textColor: color
            )

            let tag = TTGTextTag(
                content: tagContents,
                style: style,
                selectedContent: selectedTagContents,
                selectedStyle: selectedStyle
            )

            tagCollectionView.addTag(tag)
        }
    }
}


태그를 만들었다.

이제는 태그를 테이블 뷰의 헤더로 넣어야 한다.

 

        // 헤더등록 코드가 조금 다르다.
        tableView.register(
            NewsListTableViewHeaderView.self,
            forHeaderFooterViewReuseIdentifier: NewsListTableViewHeaderView.identifier
        )


태그를 헤더로 넣었으면, 아이디를 등록해준다.
태그는 View이지만 id 등록이 필요하다.

 

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let header = tableView.dequeueReusableHeaderFooterView(
            withIdentifier: NewsListTableViewHeaderView.identifier
        ) as? NewsListTableViewHeaderView
            
        header?.setup(tags: tags, delegate: self)
        
        return header
    }


기본적으로 테이블 뷰 헤더와 푸터는 딜리게이트의 해당 메서드를 통해서 구현할 수 있다.