https://github.com/boostcampwm2023/iOS07-traveline/wiki/[iOS]-단방향-플로우-ViewModel-구현기
<aside> 💡
디자인 시스템 구현
이미지
컬러셋 추가
https://velog.io/@niro/SOPT-앱잼-Xcode-15-에서-Image-Color-에-접근하는-새로운-방법
폰트 추가
텍스트 익스텐션 </aside>
https://github.com/pcsoyeon/Network
https://hyun-je.github.io/ios/2019/04/13/one_way_data_stream_viewmodel.html
https://velog.io/@wnsxor1993/MVVM-Clean-Architecture-정리 → 다이어그램
UIStackView는 기본적으로 한 방향으로만 배치됩니다. 하지만 해시태그가 여러 줄로 넘어가는 레이아웃을 구현하려면 UIStackView
를 수직 스택뷰와 수평 스택뷰를 조합하거나, **"줄바꿈이 가능한 동적 레이아웃"**을 위해 UILabel
이나 UICollectionView
대신 UIStackView
안에 컨트롤을 구성할 수 있습니다.
이 방식을 통해 태그가 화면 너비를 넘어가면, 새로운 수평 스택뷰를 추가하여 새로운 줄을 시작할 수 있습니다.
import UIKit
class ViewController: UIViewController {
let verticalStackView = UIStackView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
// 1. Vertical StackView 설정
verticalStackView.axis = .vertical
verticalStackView.spacing = 8
verticalStackView.alignment = .leading
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(verticalStackView)
// 2. Vertical StackView 레이아웃
NSLayoutConstraint.activate([
verticalStackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
verticalStackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
verticalStackView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100)
])
// 3. 태그 데이터 추가
let tags = ["핑구", "캐릭터", "펭귄", "D-5", "굿즈", "이벤트", "여의도", "더현대서울"] // 서버 데이터
addTagsToVerticalStackView(tags: tags)
}
private func addTagsToVerticalStackView(tags: [String]) {
// 한 줄에 들어갈 태그를 관리할 Horizontal StackView
var currentHorizontalStackView = createHorizontalStackView()
verticalStackView.addArrangedSubview(currentHorizontalStackView)
var currentRowWidth: CGFloat = 0
let maxWidth = view.bounds.width - 32 // 화면 너비에서 양쪽 마진(16씩)을 뺌
for tag in tags {
let tagLabel = createTagLabel(text: tag)
let tagWidth = tagLabel.intrinsicContentSize.width + 16 // 태그의 실제 너비 + padding(좌우 8씩)
// 새 줄로 넘어가야 할 경우
if currentRowWidth + tagWidth > maxWidth {
currentHorizontalStackView = createHorizontalStackView()
verticalStackView.addArrangedSubview(currentHorizontalStackView)
currentRowWidth = 0
}
// 현재 줄에 태그 추가
currentHorizontalStackView.addArrangedSubview(tagLabel)
currentRowWidth += tagWidth + 8 // 태그 간의 간격 추가
}
}
private func createHorizontalStackView() -> UIStackView {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = 8
stackView.alignment = .leading
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}
private func createTagLabel(text: String) -> UILabel {
let label = UILabel()
label.text = text
label.textColor = .white
label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
label.textAlignment = .center
label.backgroundColor = UIColor.systemBlue
label.layer.cornerRadius = 15
label.layer.masksToBounds = true
label.translatesAutoresizingMaskIntoConstraints = false
label.heightAnchor.constraint(equalToConstant: 30).isActive = true
label.widthAnchor.constraint(equalToConstant: text.size(withAttributes: [.font: UIFont.systemFont(ofSize: 14)]).width + 20).isActive = true
return label
}
}