🎯 Trouble Shooting
[ 1. 보여주는 이미지를 3개에서 1개로 변경 ]
이유 : 가게 정보에 관한 이미지를 보여주기 위해서는 Google Places API 통신을 해야 한다.
그러나 우리가 필요한 사진의 수는 한 가게당 최소 3개 이상
Google Places는 한 번의 API 통신에 한 개의 이미지만 제공한다.
따라서 가게 정보와 이미지 3개를 받아오기 위해서는 총 4번의 API 통신이 필요하다.
한정된 지원금 안에서 유료 API를 사용하다 보니 부득이하게 이미지를 1개만 사용하는 방향으로 수정하게 되었다.
[ 해당 issue 관련하여 API 문서 ]
장소 사진 (신규) | Places SDK for iOS | Google for Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 장소 사진 (신규) 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 플랫폼 선택: Android iOS
developers.google.com
[ 2. 이미지의 비율 정하기 ]
여러 번의 테스트를 해본 결과 우리 팀은 1:1 비율의 AspectFill 방법을 사용하기로 했다.
[ 우리 팀의 결정 ]
[ 3. PopUp Button의 사춘기 ]
iPhone 13 mini 기준
전체 높이 812px
SafeArea (Top) 44px
SafeArea (Bottom) 34px
812 - 44 - 34 = 734 / 2 = 367
812 / 2 = 406 - 44 = 362
SafeArea 기준으로 346 정도 offset하니 PopUp Button이 아래로 위치하게 되었다.
👨🏻💻 오늘의 작업 - UI 구현
[ 1. TableView 만들기 ]
[ 코드 ]
private let tableView: UITableView = {
let tableView = UITableView()
tableView.register(DetailTableViewCell.self, forCellReuseIdentifier: DetailTableViewCell.identifier)
return tableView
}()
private func configureUI() {
view.backgroundColor = .white
tableView.delegate = self
tableView.dataSource = self
[storeCountLabel, sortButton, tableView].forEach {
view.addSubview($0)
}
tableView.snp.makeConstraints { make in
make.top.equalTo(storeCountLabel.snp.bottom).offset(8)
make.leading.trailing.equalToSuperview()
make.bottom.equalToSuperview()
}
}
extension DetailViewController: UITableViewDataSource, UITableViewDelegate {
// 테이블 뷰 섹션 수 지정
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 테이블 뷰 셀들의 갯수
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return testArray.count
}
// 테이블 뷰 셀 지정
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: DetailTableViewCell.identifier, for: indexPath) as? DetailTableViewCell else { return UITableViewCell() }
cell.configureView()
return cell
}
// 테이블 뷰의 높이 지정
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 145
}
}
[ 2. TableView Cell 만들기 ]
[ 코드 ]
import UIKit
import SnapKit
class DetailTableViewCell: UITableViewCell {
static let identifier = "CustomTableViewCell"
private let storeNameLabel: UILabel = {
let label = UILabel()
label.text = "식당명"
label.textColor = .black
label.font = .customFontForHeader(weight: .w800)
return label
}()
private let rateImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "Star")
return imageView
}()
private let rateLabel: UILabel = {
let label = UILabel()
label.text = "평점"
label.textColor = .black
label.font = .customFontForBody(weight: .w600)
return label
}()
private let userRateCountLabel: UILabel = {
let label = UILabel()
label.text = "(리뷰수)"
label.textColor = .black
label.font = .customFontForBody(weight: .w600)
return label
}()
private let storeTypeLabel: UILabel = {
let label = UILabel()
label.text = "식당 종류"
label.textColor = .black
label.font = .customFontForBody(weight: .w500)
return label
}()
private let addressLabel: UILabel = {
let label = UILabel()
label.text = "주소"
label.textColor = .black
label.font = .customFontForBody(weight: .w500)
return label
}()
private let timeImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "Time")
return imageView
}()
private let openNowLabel: UILabel = {
let label = UILabel()
label.text = "영업전/후 • 시간"
label.textColor = .black
label.font = .customFontForBody(weight: .w500)
return label
}()
private let storeImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "Rectangle")
return imageView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configureView() {
[storeNameLabel, rateImageView, rateLabel, userRateCountLabel, storeTypeLabel, addressLabel, timeImageView, openNowLabel, storeImageView].forEach {
contentView.addSubview($0)
}
storeNameLabel.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.top.equalToSuperview().offset(26)
make.width.equalTo(242)
make.height.equalTo(25)
}
rateImageView.snp.makeConstraints { make in
make.width.height.equalTo(14)
make.leading.equalToSuperview().offset(20)
make.top.equalTo(storeNameLabel.snp.bottom).offset(7)
}
rateLabel.snp.makeConstraints { make in
make.height.equalTo(20)
make.width.equalTo(25)
make.leading.equalTo(rateImageView.snp.trailing).offset(4)
make.centerY.equalTo(rateImageView)
}
userRateCountLabel.snp.makeConstraints { make in
make.leading.equalTo(rateLabel.snp.trailing).offset(4)
make.centerY.equalTo(rateImageView)
make.height.equalTo(20)
make.width.equalTo(48)
}
storeTypeLabel.snp.makeConstraints { make in
make.leading.equalTo(userRateCountLabel.snp.trailing).offset(4)
make.centerY.equalTo(rateImageView)
make.height.equalTo(18)
make.width.equalTo(143)
}
addressLabel.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.top.equalTo(rateLabel.snp.bottom).offset(4)
make.height.equalTo(18)
make.width.equalTo(242)
}
timeImageView.snp.makeConstraints { make in
make.leading.equalToSuperview().offset(20)
make.width.height.equalTo(16)
make.top.equalTo(addressLabel.snp.bottom).offset(5)
}
openNowLabel.snp.makeConstraints { make in
make.width.equalTo(222)
make.height.equalTo(18)
make.leading.equalTo(timeImageView.snp.trailing).offset(4)
make.centerY.equalTo(timeImageView)
}
storeImageView.snp.makeConstraints { make in
make.height.width.equalTo(93)
make.leading.equalTo(storeNameLabel.snp.trailing)
make.top.equalToSuperview().offset(26)
}
}
}
[ 3. keynote Data Flow 작성 ]
[ 4. PopUp Button UI 구현 ]
[ 코드 ]
private let sortButton: UIButton = {
var config = UIButton.Configuration.plain()
let font = UIFont.customFontForSubtitle(weight: .w600)
let title = "별점순"
let attributedTitle = AttributedString(title, attributes: AttributeContainer([.font: font]))
config.attributedTitle = attributedTitle
config.image = UIImage(named: "ChevronDown")
config.imagePadding = 2 // 텍스트와 이미지 사이 간격
config.imagePlacement = .trailing // 텍스트 오른쪽에 이미지
let button = UIButton(configuration: config, primaryAction: nil)
button.tintColor = .black
let updateTitle: (String) -> Void = { newTitle in
var updatedConfig = button.configuration
let attributedTitle = AttributedString(newTitle, attributes: AttributeContainer([.font: font]))
updatedConfig?.attributedTitle = attributedTitle
button.configuration = updatedConfig
}
let menuItems = [
UIAction(title: "별점순", handler: { _ in updateTitle("별점순") }),
UIAction(title: "거리순", handler: { _ in updateTitle("거리순") }),
UIAction(title: "리뷰순", handler: { _ in updateTitle("리뷰순") }),
UIAction(title: "가격순", handler: { _ in updateTitle("가격순") })
]
button.menu = UIMenu(title: "", options: .displayInline , children: menuItems)
button.showsMenuAsPrimaryAction = true
button.contentHorizontalAlignment = .leading
return button
}()
'스파르타 코딩 클럽 - iOS 스타터 6기 > 본 캠프' 카테고리의 다른 글
63. 스파르타 코딩 클럽 - 최종 팀 프로젝트 #5 (0) | 2025.06.12 |
---|---|
62. 스파르타 코딩 클럽 - 최종 팀 프로젝트 #4 (0) | 2025.06.11 |
59. 스파르타 코딩 클럽 - 최종 팀 프로젝트 #2 (0) | 2025.06.06 |
57. 스파르타 코딩 클럽 - 최종 팀 프로젝트 #1 (2) | 2025.06.04 |
56. 스파르타 코딩 클럽 - 봄여어름갈겨어울 #6 (날씨앱) (0) | 2025.05.27 |