728x90
예전의 프로젝트에서는 ViewController의 UINavigationController나 navigationItem에 직접 접근하여 UINavigation을 사용하였다. 물론 이 방법이 정석이지만, 커스텀을 하다보면 버튼의 위치를 설정한다던지, 타이틀의 폰트를 변경한다던지 등 불편한 점이 많았다.
Header View
직접 커스텀 View를 만들어서 사용하면 좋지 않을까? 하는 생각이 들었고, CollectionView의 Header & Footer가 생각이 났다.
import UIKit
import RxCocoa
import RxSwift
import SnapKit
import Then
protocol FeedHeaderViewDelegate: AnyObject {
func didAddVoteButtonTapped()
}
class FeedHeaderView: UIView {
private let disposeBag = DisposeBag()
weak var delegate: FeedHeaderViewDelegate?
// MARK: - UI Components
private let title = UILabel().then {
let attributedString = NSMutableAttributedString(string: "사카", attributes: [.font: UIFont.h2, .foregroundColor: UIColor.Turquoise])
attributedString.append(NSAttributedString(string: "마카", attributes: [.font: UIFont.h2_2, .foregroundColor: UIColor.black]))
$0.attributedText = attributedString
}
private let addVoteButton = UIButton().then {
$0.setImage(UIImage(systemName: "plus"), for: .normal)
$0.tintColor = .nightGray
$0.backgroundColor = .milkWhite
$0.layer.cornerRadius = 5
}
// MARK: - Init
override init(frame: CGRect) {
super.init(frame: frame)
setView()
setConstraint()
bind()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - SetUp View
private func setView() {
backgroundColor = .clear
[title, addVoteButton].forEach { addSubview($0) }
}
private func setConstraint() {
title.snp.makeConstraints {
$0.centerY.equalToSuperview()
$0.leading.equalToSuperview().inset(20)
}
addVoteButton.snp.makeConstraints {
$0.centerY.equalToSuperview()
$0.width.height.equalTo(30)
$0.trailing.equalToSuperview().inset(20)
}
}
private func bind() {
addVoteButton.rx.tap
.subscribe(with: self, onNext: { owner, _ in
owner.delegate?.didAddVoteButtonTapped()
})
.disposed(by: disposeBag)
}
}
커스텀 View에 UI 요소와 제약조건을 설정하고, Button의 Tapped 이벤트를 delegate로 처리하도록 구현하였다.
import UIKit
import RxCocoa
import RxSwift
import SnapKit
import Then
class FeedViewController: BaseViewController {
...
// MARK: - UI Components
private lazy var headerView = FeedHeaderView().then {
$0.delegate = self
}
// MARK: - SetUp VC
override func setViewController() {
[headerView, feedCollectionView].forEach { view.addSubview($0) }
}
...
override func setConstraints() {
headerView.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide)
$0.horizontalEdges.equalToSuperview()
$0.height.equalTo(32)
}
feedCollectionView.snp.makeConstraints {
$0.top.equalTo(headerView.snp.bottom).offset(20)
$0.bottom.equalTo(view.safeAreaLayoutGuide).inset(20)
$0.horizontalEdges.equalTo(view.safeAreaLayoutGuide).inset(20)
}
}
...
}
extension FeedViewController: FeedHeaderViewDelegate {
func didAddVoteButtonTapped() {
let vc = AddVoteViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
}
해당 HeaderView를 사용하고자 하는 ViewController에서 headerView를 선언하고 추가해준다. 그리고 제약조건을 설정하고 HeaderView의 버튼 이벤트를 위임 받아서 구현해주면 된다.
정상적으로 적용이 됐다 !
내 생각
1. 필요한 ViewController마다 일일이 구현해줘야 한다는 귀찮음이 있지만, 기존의 방법보다 직관적이고 관리하기가 쉽다는 장점이 더 큰 것 같다.
2. NavigationBar에 TextField를 넣는(검색 기능) 등 복잡하게 커스텀 할 때 사용하기 좋을 것 같다.
3. BackButton과 Title만 필요한 ViewController에서는 재사용 HeaderView를 만들어서 사용하면 더 좋을 것 같다.
'ToyProject - 사카마카 (살까말까 고민 될 때는 사카마카)' 카테고리의 다른 글
[사카마카] 키보드 이벤트를 감지하여 화면의 레이아웃을 업데이트 해보자. (0) | 2024.06.01 |
---|---|
[사카마카/문제해결] 앱 내에서 웹을 보여줄 때 발생하는 스킴 문제를 해결해보자. (0) | 2024.05.30 |
[사카마카] 앱 내에서 웹을 보여주는 방법에 대해 알아보자. (0) | 2024.05.30 |
[사카마카] Lottie로 애니메이션을 사용해보자. (0) | 2024.05.29 |
[사카마카/문제해결] CollectionViewCell의 버튼 이벤트 문제를 해결해보자. (0) | 2024.05.29 |