🟨 구현화면
🟨 구현 순서
- navigationItem 의 titleView에 logo 이미지 설정
- profile 관련된 Controller 및 profileView 생성
🟨 HomeViewController.swift 코드 구현
- configureNavigationBar() 메서드로 네비게이션 부분 설정
- 로고를 네비게이션에 할당: 1. 로고 이미지뷰 생성 및 설정 → 2. 로고 이미지뷰를 담을 뷰 생성 → 3. 해당 뷰를 네비게이션에 설정
import UIKit
class HomeViewController: UIViewController {
// 네비게이션 부분에 logo 이미지 추가
private func configureNavigationBar() {
let size: CGFloat = 36
let logoImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: size, height: size))
logoImageView.contentMode = .scaleAspectFill
logoImageView.image = UIImage(named: "logo")
let middleView = UIView(frame: CGRect(x: 0, y: 0, width: size, height: size))
middleView.addSubview(logoImageView)
navigationItem.titleView = middleView
// profile
let profileImage = UIImage(systemName: "person")
navigationItem.leftBarButtonItem = UIBarButtonItem(image: profileImage, style: .plain, target: self, action: #selector(didTapProfile))
}
@objc private func didTapProfile() {
print("didTapProfile() - called")
let profileVC = ProfileViewController()
navigationController?.pushViewController(profileVC, animated: true)
}
private let timelineTableView: UITableView = {
let tableView = UITableView()
tableView.register(TweetTableViewCell.self, forCellReuseIdentifier: TweetTableViewCell.identifier)
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(timelineTableView)
timelineTableView.delegate = self
timelineTableView.dataSource = self
configureNavigationBar()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
timelineTableView.frame = view.bounds
}
}
extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: TweetTableViewCell.identifier,
for: indexPath) as? TweetTableViewCell
else {
return UITableViewCell()
}
// 델리게이트 패턴에 대한 대리자를 HomeViewController 설정
cell.delegate = self
return cell
}
}
extension HomeViewController: TweetTableViewCellDelegate {
func tweetTableViewCellDidTapReply() {
print("tweetTableViewCellDidTapReply() - called")
}
func tweetTableViewCellDidTapRetweet() {
print("tweetTableViewCellDidTapRetweet() - called")
}
func tweetTableViewCellDidTapLike() {
print("tweetTableViewCellDidTapLike() - called")
}
func tweetTableViewCellDidTapShare() {
print("tweetTableViewCellDidTapShare() - called")
}
}
🟨 ProfileViewController.swift 코드 구현
- 기존에 사용했던 TweetTableViewCell을 사용하여 테이블 뷰의 레이아웃을 잡는다.
- tableHeaderView를 통해 table의 Header 부분에 Profile 내용을 담는다.
import UIKit
class ProfileViewController: UIViewController {
private let profileTableView: UITableView = {
let tableView = UITableView()
tableView.register(TweetTableViewCell.self, forCellReuseIdentifier: TweetTableViewCell.identifier)
tableView.translatesAutoresizingMaskIntoConstraints = false
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
navigationItem.title = "Profile"
view.addSubview(profileTableView)
profileTableView.delegate = self
profileTableView.dataSource = self
configureConstraints()
let headerView = ProfileTableViewHeader(frame: CGRect(x: 0, y: 0, width: profileTableView.frame.width, height: 350))
profileTableView.tableHeaderView = headerView
}
private func configureConstraints() {
let profileTableViewConstraints = [
profileTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
profileTableView.topAnchor.constraint(equalTo: view.topAnchor),
profileTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
profileTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
]
NSLayoutConstraint.activate(profileTableViewConstraints)
}
}
extension ProfileViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: TweetTableViewCell.identifier, for: indexPath) as? TweetTableViewCell else { return TweetTableViewCell() }
return cell
}
}
🟨 ProfileTableViewHeader.swfit 코드 구현
import UIKit
class ProfileTableViewHeader: UIView {
private let joinDateLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Joined May 2024"
label.textColor = .secondaryLabel
label.font = .systemFont(ofSize: 14, weight: .regular)
return label
}()
private let joinDateImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.image = UIImage(systemName: "calendar", withConfiguration: UIImage.SymbolConfiguration(pointSize: 14))
imageView.tintColor = .secondaryLabel
return imageView
}()
private let userBioLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 3
label.textColor = .label
label.text = "iOS Developer"
return label
}()
private let userNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "@Explorer"
label.textColor = .secondaryLabel
label.font = .systemFont(ofSize: 18, weight: .regular)
return label
}()
private let displayNameLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.text = "Explorer"
label.font = .systemFont(ofSize: 22, weight: .bold)
return label
}()
private let profileAvatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 40
imageView.layer.masksToBounds = true
imageView.image = UIImage(named: "profile")
imageView.backgroundColor = .systemYellow
return imageView
}()
private let profileHeaderImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.image = UIImage(named: "header")
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
// backgroundColor = .systemBlue
addSubview(profileHeaderImageView)
addSubview(profileAvatarImageView)
addSubview(displayNameLabel)
addSubview(userNameLabel)
addSubview(userBioLabel)
addSubview(joinDateImageView)
addSubview(joinDateLabel)
configureConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configureConstraints() {
let profileHeaderImageViewConstraints = [
profileHeaderImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
profileHeaderImageView.topAnchor.constraint(equalTo: topAnchor),
profileHeaderImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
profileHeaderImageView.heightAnchor.constraint(equalToConstant: 100)
]
let profileAvatarImageViewConstraints = [
profileAvatarImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
profileAvatarImageView.centerYAnchor.constraint(equalTo: profileHeaderImageView.bottomAnchor, constant: 10),
profileAvatarImageView.widthAnchor.constraint(equalToConstant: 80),
profileAvatarImageView.heightAnchor.constraint(equalToConstant: 80)
]
let displayNameLabelConstraints = [
displayNameLabel.leadingAnchor.constraint(equalTo: profileAvatarImageView.leadingAnchor),
displayNameLabel.topAnchor.constraint(equalTo: profileAvatarImageView.bottomAnchor, constant: 20)
]
let userNameLabelConstraints = [
userNameLabel.leadingAnchor.constraint(equalTo: displayNameLabel.leadingAnchor),
userNameLabel.topAnchor.constraint(equalTo: displayNameLabel.bottomAnchor, constant: 5)
]
let userBioLabelConstraints = [
userBioLabel.leadingAnchor.constraint(equalTo: displayNameLabel.leadingAnchor),
// userBioLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -5),
userBioLabel.topAnchor.constraint(equalTo: userNameLabel.bottomAnchor, constant: 5)
]
let joinDateImageViewConstraints = [
joinDateImageView.leadingAnchor.constraint(equalTo: displayNameLabel.leadingAnchor),
joinDateImageView.topAnchor.constraint(equalTo: userBioLabel.bottomAnchor, constant: 5)
]
let joinDateLabelConstraints = [
joinDateLabel.leadingAnchor.constraint(equalTo: joinDateImageView.trailingAnchor, constant: 2),
joinDateLabel.bottomAnchor.constraint(equalTo: joinDateImageView.bottomAnchor)
]
NSLayoutConstraint.activate(profileHeaderImageViewConstraints)
NSLayoutConstraint.activate(profileAvatarImageViewConstraints)
NSLayoutConstraint.activate(displayNameLabelConstraints)
NSLayoutConstraint.activate(userNameLabelConstraints)
NSLayoutConstraint.activate(userBioLabelConstraints)
NSLayoutConstraint.activate(joinDateImageViewConstraints)
NSLayoutConstraint.activate(joinDateLabelConstraints)
}
}
🟨 TIL
- 어떤 문제가 있었는지?
- 로고가 원하는 크기에 맞지 않게 출력됨
- logo 이미지를 UIImageView 타입의 logoImageView에 담는다.
- logoImageView를 navigationItem.titleView에 할당한다.
- 근데 이러면 로고가 네비게이션 부분을 벗어난다.
private func configureNavigationBar() {
let size: CGFloat = 36
let logoImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: size, height: size))
logoImageView.contentMode = .scaleAspectFill
logoImageView.image = UIImage(named: "logo")
navigationItem.titleView = logoImageView
}
- 아래와 같이 코드를 설정하면 네비게이션 부분에 맞게 나오긴 하는데... 크기가 내가 처음 설정한 크기에 맞게 나오는게 아니라 비율에 따라 맞춰들어가기 때문에 안된다.
logoImageView.contentMode = .scaleAspectFit
- 어떻게 해결했는지
- UIView 타입의 middleView를 크기와 위치를 logoImageView와 동일하게 해서 생성
- middleView에 logoImageView를 삽입
- navigationItem의 TitleView에 middleView 할당
- 단, logoImageView.contentMode = .scaleAspectFill
private func configureNavigationBar() {
let size: CGFloat = 36
let logoImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: size, height: size))
logoImageView.contentMode = .scaleAspectFill
logoImageView.image = UIImage(named: "logo")
let middleView = UIView(frame: CGRect(x: 0, y: 0, width: size, height: size))
middleView.addSubview(logoImageView)
navigationItem.titleView = middleView
....
로고 이미지가 36에 맞게 나온 거 같다.?
(이미지 크기를 확인하고 싶은데.. 어떻게 하는거지..)
✅ 시스템 이미지 크기 조절
imageView.image = UIImage(systemName: "calendar", withConfiguration: UIImage.SymbolConfiguration(pointSize: 14))
https://youtu.be/scqLiVBWhg0?si=Ccs7EmZUFp6TsOK0
'Clone App > Twitter' 카테고리의 다른 글
[Twitter Clone] Add Indicator button in profile view (0) | 2024.05.27 |
---|---|
[Twitter Clone] Continue implementing the profile view (0) | 2024.05.27 |
[Twitter Clone] Add tweet actions (0) | 2024.05.24 |
[Twitter Clone] Add a custom cell (0) | 2024.05.24 |
[Twitter Clone] Setup the basic layout (0) | 2024.05.23 |