24.07.04 Today I Learned
2024. 7. 4. 21:06
// Model.swift
import Foundation
struct CoffeeList{
let imageName: String
let menuName: String
let menuPrice: Int
}
extension CoffeeList{
static let recommended_Menu = [
CoffeeList(imageName: "plain_PongCrush", menuName: "플레인퐁크러쉬", menuPrice: 4500),
CoffeeList(imageName: "iced_Cue_Brat", menuName: "아이스큐브라떼", menuPrice: 5200),
CoffeeList(imageName: "grapefruit_Ade", menuName: "자몽에이드", menuPrice: 4800),
CoffeeList(imageName: "iced_Apple_and_Citrus_Tea", menuName: "아이스사과유자차", menuPrice: 5000),
CoffeeList(imageName: "strawberry_Latte", menuName: "딸기라떼", menuPrice: 5300),
CoffeeList(imageName: "potato_Bread", menuName: "감자빵", menuPrice: 4200)
]
static let smoothie_Menu = [
CoffeeList(imageName: "golden_Mango_Smoothie", menuName: "골드망고스무디", menuPrice: 5800),
CoffeeList(imageName: "strawberry_Yogurt_Smoothie", menuName: "딸기요거트스무디", menuPrice: 5500),
CoffeeList(imageName: "strawberry_Cookie_Frappe", menuName: "딸기쿠키프라페", menuPrice: 5700),
CoffeeList(imageName: "cookie_Frappe", menuName: "쿠키프라페", menuPrice: 5600),
CoffeeList(imageName: "coconut_Coffee_Smoothie", menuName: "코코넛커피스무디", menuPrice: 5900),
CoffeeList(imageName: "mint_Frappe", menuName: "민트프라페", menuPrice: 5400)
]
static let coffee_Menu = [
CoffeeList(imageName: "iced_Vanilla_Latte", menuName: "아이스바닐라라떼", menuPrice: 4900),
CoffeeList(imageName: "iced_Americano", menuName: "아이스아메리카노", menuPrice: 4000),
CoffeeList(imageName: "iscafemoca", menuName: "아이스카페모카", menuPrice: 5300),
CoffeeList(imageName: "big_Hal_Mega_Coffee", menuName: "왕할메가커피", menuPrice: 6000),
CoffeeList(imageName: "cold_Brew_Latte", menuName: "콜드브루라떼", menuPrice: 5100),
CoffeeList(imageName: "iscara_melmakiatto", menuName: "아이스카라멜마끼아또", menuPrice: 5500)
]
static let dessert_Menu = [
CoffeeList(imageName: "honey_bread", menuName: "허니브레드", menuPrice: 7000),
CoffeeList(imageName: "hot_Chicken_Deep_Cheese_Ciabatta", menuName: "핫 치킨&딥치즈 치아바타", menuPrice: 6500),
CoffeeList(imageName: "cheesecake", menuName: "치즈케익", menuPrice: 5800),
CoffeeList(imageName: "choco_Gelato_Croiffle", menuName: "초코젤라또크로플", menuPrice: 7200),
CoffeeList(imageName: "iced_Honey_Waansu", menuName: "아이스허니와앙슈", menuPrice: 5000),
CoffeeList(imageName: "butter_Egg_Bacon_Sandwich", menuName: "버터버터에그베이컨샌드위치", menuPrice: 6900)
]
static let beverage_Menu = [
CoffeeList(imageName: "cherry_Coke", menuName: "체리콕", menuPrice: 4500),
CoffeeList(imageName: "ice_Choco", menuName: "아이스초코", menuPrice: 4700),
CoffeeList(imageName: "ice_Grain_Latte", menuName: "아이스곡물라떼", menuPrice: 4800),
CoffeeList(imageName: "peach_Ice_Tea", menuName: "복숭아아이스티", menuPrice: 4500),
CoffeeList(imageName: "shine_Musket_Green", menuName: "샤인머스캣그린주스", menuPrice: 5200),
CoffeeList(imageName: "strawberry_Banana", menuName: "딸기바나나주스", menuPrice: 5300)
]
static let do_not_eat_Menu = [
CoffeeList(imageName: "wm_Juice", menuName: "수박주스", menuPrice: 5000),
CoffeeList(imageName: "bsbubblemt_Icedlatte", menuName: "흑당버블밀크티아이스라떼", menuPrice: 5500),
CoffeeList(imageName: "bs_Icedbubblelatte", menuName: "흑당아이스버블라떼", menuPrice: 5500),
CoffeeList(imageName: "cucumber_Limemojito", menuName: "오이오이라임오히또", menuPrice: 4800),
CoffeeList(imageName: "grapefruit_honey_bt_Iced", menuName: "아이스허니자몽블랙티", menuPrice: 4900),
CoffeeList(imageName: "ggultip_Option", menuName: "꿀팁옵션", menuPrice: 3800)
]
static let tea_Menu = [
CoffeeList(imageName: "chamomile_Tea", menuName: "캐모마일티", menuPrice: 5000),
CoffeeList(imageName: "citron_Tea", menuName: "유자차", menuPrice: 5500),
CoffeeList(imageName: "earlGrey_Tea", menuName: "얼그레이티", menuPrice: 5500),
CoffeeList(imageName: "green_Tea", menuName: "녹차", menuPrice: 4800),
CoffeeList(imageName: "honey_Grapefruit_BlackTea", menuName: "허니자몽블랙티", menuPrice: 4900),
CoffeeList(imageName: "", menuName: "로얄밀크티", menuPrice: 5000)
]
// static let pong_crush_Menu = [
// CoffeeList(imageName: "choco_Honey_PongCrush", menuName: "초코허니퐁크러쉬", menuPrice: 5300),
// CoffeeList(imageName: "banana_PongCrush", menuName: "바나나퐁크러쉬", menuPrice: 5200),
// CoffeeList(imageName: "strawberry_PongCrush", menuName: "딸기퐁크러쉬", menuPrice: 5400),
// CoffeeList(imageName: "plain_PongCrush", menuName: "플레인퐁크러쉬", menuPrice: 4500),
// CoffeeList(imageName: "custardCream_Honey_PongCrush", menuName: "슈크림허니퐁크러쉬", menuPrice: 5600)
// ]
}
// Category.swift
import UIKit
import SnapKit
protocol CoffeeListViewDelegate: AnyObject {
func segmentValueChanged(to index: Int)
func configureCollectionViewConstraints()
func configureCollectionViewAppearance()
}
class CategoryView: UIView {
weak var delegate: CoffeeListViewDelegate?
let categories = ["추천메뉴", "커피", "디저트", "스무디", "티", "비추천메뉴"]
var drinks: [[CoffeeList]] = [] // 컬렉션 뷰 데이터를 담을 배열
lazy var segmentControl: UISegmentedControl = {
let control = UISegmentedControl(items: categories)
control.selectedSegmentIndex = 0
control.addTarget(self, action: #selector(segmentValueChanged(_:)), for: .valueChanged)
control.translatesAutoresizingMaskIntoConstraints = false
control.backgroundColor = .white
control.tintColor = .white
control.selectedSegmentTintColor = .clear
control.apportionsSegmentWidthsByContent = true // 텍스트 길이에 맞게 너비 조절
let normalTextAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 14) // 글자 크기를 축소하여 모든 텍스트가 보이도록 설정
]
control.setTitleTextAttributes(normalTextAttributes, for: .normal)
let selectedTextAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 14) // 선택된 상태의 글자 크기도 축소
]
control.setTitleTextAttributes(selectedTextAttributes, for: .selected)
return control
}()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 10
let view = UICollectionView(frame: .zero, collectionViewLayout: layout)
view.backgroundColor = .white
view.delegate = self
view.dataSource = self
view.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var logoImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "logo")
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupViews() {
setupLogo()
setupSegmentControl()
setupCollectionView()
drinks = [CoffeeList.recommended_Menu, CoffeeList.coffee_Menu, CoffeeList.dessert_Menu, CoffeeList.smoothie_Menu, CoffeeList.tea_Menu, CoffeeList.do_not_eat_Menu]
collectionView.reloadData()
}
private func setupLogo() {
addSubview(logoImageView)
logoImageView.snp.makeConstraints { make in
make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(0)
make.centerX.equalToSuperview()
make.width.equalTo(200)
make.height.equalTo(100)
}
}
private func setupSegmentControl() {
addSubview(segmentControl)
segmentControl.snp.makeConstraints { make in
make.top.equalTo(logoImageView.snp.bottom).offset(20)
make.left.right.equalToSuperview().inset(20)
}
}
private func setupCollectionView() {
addSubview(collectionView)
collectionView.snp.makeConstraints { make in
make.top.equalTo(segmentControl.snp.bottom).offset(20)
make.left.right.equalToSuperview().inset(20)
make.height.equalTo(300)
}
delegate?.configureCollectionViewConstraints()
}
@objc private func segmentValueChanged(_ sender: UISegmentedControl) {
delegate?.segmentValueChanged(to: sender.selectedSegmentIndex)
}
}
extension CategoryView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return drinks[segmentControl.selectedSegmentIndex].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
for subview in cell.contentView.subviews {
subview.removeFromSuperview()
}
let coffee = drinks[segmentControl.selectedSegmentIndex][indexPath.item]
let imageView = UIImageView()
imageView.image = UIImage(named: coffee.imageName)
imageView.contentMode = .scaleAspectFit
cell.contentView.addSubview(imageView)
imageView.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(5)
}
let label = UILabel()
label.text = "\(coffee.menuName) - \(coffee.menuPrice)원"
label.textAlignment = .center
label.backgroundColor = .white
label.clipsToBounds = true
label.numberOfLines = 0
label.lineBreakMode = .byTruncatingTail // Truncate tail for long text
label.font = UIFont.systemFont(ofSize: 14) // 글자 크기 축소
cell.contentView.addSubview(label)
label.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview().inset(5)
make.top.equalTo(imageView.snp.bottom).offset(5)
}
return cell
}
}
extension CategoryView: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 100, height: 150)
}
}
// ViewController.swift
import UIKit
import SnapKit
class ViewController: UIViewController {
let coffeeListView = CategoryView()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupCoffeeListView()
}
private func setupCoffeeListView() {
coffeeListView.delegate = self
view.addSubview(coffeeListView)
coffeeListView.snp.makeConstraints { make in
make.edges.equalToSuperview().inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}
}
}
extension ViewController: CoffeeListViewDelegate {
func segmentValueChanged(to index: Int) {
coffeeListView.collectionView.reloadData()
}
func configureCollectionViewConstraints() {
// Additional constraints can be added here if needed
}
func configureCollectionViewAppearance() {
coffeeListView.collectionView.backgroundColor = .white
}
}
=======
내 코드는 이렇게 MVC를 나눠서 작성했다.
위 사진은 컬렉션뷰 파트를 맡은 인원과 내 코드를 합쳐서 만든 뷰다.
// Category.swift
// 카테고리
import UIKit
import SnapKit
protocol CoffeeListViewDelegate: AnyObject {
func segmentValueChanged(to index: Int)
}
class CategoryView: UIView {
weak var delegate: CoffeeListViewDelegate?
private let categories = ["추천메뉴", "커피", "디저트", "스무디", "티", "비추천메뉴"]
// 컬렉션 뷰 데이터를 담을 배열
var drinks: [[CoffeeList]] = []
// 세그먼트 컨트롤 관련 세부설정
lazy var segmentControl: UISegmentedControl = {
let control = UISegmentedControl(items: categories)
control.selectedSegmentIndex = 0
control.addTarget(self, action: #selector(segmentValueChanged(_:)), for: .valueChanged)
control.backgroundColor = .white
control.tintColor = .white
control.selectedSegmentTintColor = .clear
control.apportionsSegmentWidthsByContent = true
// 폰트 설정
let normalTextAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 14)
]
control.setTitleTextAttributes(normalTextAttributes, for: .normal)
let selectedTextAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 14)
]
control.setTitleTextAttributes(selectedTextAttributes, for: .selected)
return control
}()
// 로고 이미지 뷰 생성
lazy var logoImageView: UIImageView = {
let img = UIImageView()
img.contentMode = .scaleAspectFit
img.image = UIImage(named: "logo")
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// 뷰 설정 함수
private func setupViews() {
addSubview(logoImageView)
// addSubview(segmentControl)
// 세그먼트 컨트롤 관련 카테고리
// drinks = [CoffeeList.recommended_Menu, CoffeeList.coffee_Menu, CoffeeList.dessert_Menu, CoffeeList.smoothie_Menu, CoffeeList.tea_Menu, CoffeeList.do_not_eat_Menu]
// setupLayout()
}
// private func setupLayout() {
// logoImageView.snp.makeConstraints { make in
// make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(20)
// make.centerX.equalToSuperview()
// make.width.equalTo(200)
// make.height.equalTo(100)
// }
//
// segmentControl.snp.makeConstraints { make in
// make.top.equalTo(logoImageView.snp.bottom).offset(20)
// make.left.right.equalToSuperview().inset(20)
// }
// }
// 세그먼트 컨트롤 값 변경 시 호출되는 함수
@objc private func segmentValueChanged(_ sender: UISegmentedControl) {
delegate?.segmentValueChanged(to: sender.selectedSegmentIndex)
}
}
위 코드에서 주석처리 된 부분은 C부분에서 SBMenuController.swift에서 컬렉션뷰를 구성할 때 겹치는 코드여서 주석처리했다.
// MenuView.swift
import UIKit
import SnapKit
class MenuView: UICollectionViewCell {
// 이미지 뷰 생성
let imgView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFit
return iv
}()
// 레이블 뷰 생성
let label: UILabel = {
let lbl = UILabel()
lbl.textAlignment = .center
lbl.backgroundColor = .white
lbl.clipsToBounds = true
lbl.numberOfLines = 0
lbl.lineBreakMode = .byTruncatingTail
lbl.font = UIFont.systemFont(ofSize: 14)
return lbl
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imgView)
contentView.addSubview(label)
setupLayout()
}
required init?(coder: NSCoder) {
fatalError("*T_T*")
}
// 레이아웃 설정
private func setupLayout() {
imgView.snp.makeConstraints { make in
make.top.left.right.equalToSuperview().inset(5)
make.height.equalTo(contentView.snp.height).multipliedBy(0.6)
}
label.snp.makeConstraints { make in
make.top.equalTo(imgView.snp.bottom).offset(5)
make.left.right.bottom.equalToSuperview().inset(5)
}
}
}
// SBMenuController.swift
import UIKit
import SnapKit
class SBMenuController: UIViewController {
// 컬렉션 뷰 생성
let collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
return cv
}()
// 카테고리 종류 생성
let categories = ["추천메뉴", "커피", "디저트", "스무디", "티", "비추천메뉴"]
// 카테고리 메뉴 배열
var drinks: [[CoffeeList]] = [CoffeeList.recommended_Menu, CoffeeList.coffee_Menu, CoffeeList.dessert_Menu, CoffeeList.smoothie_Menu, CoffeeList.tea_Menu, CoffeeList.do_not_eat_Menu]
var currentCategoryIndex: Int = 0
// 로고 이미지 설정
lazy var logoImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.image = UIImage(named: "logo")
return imageView
}()
// 세그먼트 컨트롤 생성
lazy var segmentControl: UISegmentedControl = {
let control = UISegmentedControl(items: categories)
control.selectedSegmentIndex = 0
control.addTarget(self, action: #selector(segmentValueChanged(_:)), for: .valueChanged)
control.backgroundColor = .white
control.tintColor = .white
control.selectedSegmentTintColor = .clear
control.apportionsSegmentWidthsByContent = true
let normalTextAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: 14)
]
control.setTitleTextAttributes(normalTextAttributes, for: .normal)
let selectedTextAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 14)
]
control.setTitleTextAttributes(selectedTextAttributes, for: .selected)
return control
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
collectionView.dataSource = self
collectionView.delegate = self
setupLayout()
}
// 레이아웃 설정
private func setupLayout() {
[logoImageView, segmentControl, collectionView].forEach {
view.addSubview($0)
}
logoImageView.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(20)
$0.centerX.equalToSuperview()
$0.width.equalTo(200)
$0.height.equalTo(100)
}
segmentControl.snp.makeConstraints {
$0.top.equalTo(logoImageView.snp.bottom).offset(20)
$0.left.right.equalToSuperview().inset(20)
}
collectionView.snp.makeConstraints {
$0.top.equalTo(segmentControl.snp.bottom).offset(20)
$0.leading.trailing.bottom.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 20, bottom: 20, right: 20))
}
collectionView.register(MenuView.self, forCellWithReuseIdentifier: "img")
}
@objc private func segmentValueChanged(_ sender: UISegmentedControl) {
currentCategoryIndex = sender.selectedSegmentIndex
collectionView.reloadData()
}
}
extension SBMenuController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return drinks[currentCategoryIndex].count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "img", for: indexPath) as! MenuView
let menuItem = drinks[currentCategoryIndex][indexPath.item]
cell.imgView.image = UIImage(named: menuItem.imageName)
cell.label.text = "\(menuItem.menuName) - \(menuItem.menuPrice)원"
return cell
}
}
extension SBMenuController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 110, height: 130)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 80
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
}
// ViewController.swift
import UIKit
import SnapKit
import SwiftUI
class ViewController: UIViewController {
let menuController = SBMenuController()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupMenuController()
}
private func setupMenuController() {
addChild(menuController)
view.addSubview(menuController.view)
menuController.didMove(toParent: self)
menuController.view.snp.makeConstraints { make in
make.edges.equalToSuperview()
}
}
}
struct PreView123: PreviewProvider {
static var previews: some View {
ViewController().toPreview123()
}
}
'Today I Learned > 2024' 카테고리의 다른 글
24.07.11 Today I Learned (0) | 2024.07.11 |
---|---|
24.07.08 Today I Learned (0) | 2024.07.08 |
24.07.02 Today I Learned (0) | 2024.07.02 |
24.07.01 Today I Learned (0) | 2024.07.01 |
24.06.28 Today I Learned (0) | 2024.06.28 |