Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: 지도 탭 캐러셀 구현 + Extension 분리 #39

Merged
merged 5 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions iOS/Layover/Layover.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
FC2511AD2B04EACD004717BC /* MapInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC2511AC2B04EACD004717BC /* MapInteractor.swift */; };
FC2511AF2B04EAD9004717BC /* MapPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC2511AE2B04EAD9004717BC /* MapPresenter.swift */; };
FC2511B12B04EAEC004717BC /* MapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC2511B02B04EAEC004717BC /* MapModels.swift */; };
FC3F3BD82B069EB30080E3A6 /* MapCarouselCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC3F3BD72B069EB30080E3A6 /* MapCarouselCollectionViewCell.swift */; };
FC49758F2B03432800D8627F /* Pretendard-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FC4975862B03432700D8627F /* Pretendard-SemiBold.ttf */; };
FC4975932B03432800D8627F /* Pretendard-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FC49758A2B03432800D8627F /* Pretendard-Bold.ttf */; };
FC4975942B03432800D8627F /* Pretendard-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FC49758B2B03432800D8627F /* Pretendard-Regular.ttf */; };
Expand All @@ -73,6 +74,7 @@
FC7E45922AFF747A004F155A /* DummyScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7E45912AFF747A004F155A /* DummyScene.swift */; };
FC7E45942AFF7486004F155A /* DummyDesignSystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7E45932AFF7486004F155A /* DummyDesignSystem.swift */; };
FC7E45962AFF7497004F155A /* DummyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7E45952AFF7497004F155A /* DummyExtension.swift */; };
FC9BB82C2B094E5500EB72A9 /* UICollectionViewLayout+.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC9BB82B2B094E5500EB72A9 /* UICollectionViewLayout+.swift */; };
FCEE0FF22B036B6000195BBE /* LOButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEE0FF12B036B6000195BBE /* LOButton.swift */; };
FCEE0FF62B03804000195BBE /* LOTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEE0FF52B03804000195BBE /* LOTextField.swift */; };
FCEE0FFA2B03AF8500195BBE /* SignUpViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEE0FF92B03AF8400195BBE /* SignUpViewController.swift */; };
Expand Down Expand Up @@ -132,6 +134,7 @@
FC2511AC2B04EACD004717BC /* MapInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapInteractor.swift; sourceTree = "<group>"; };
FC2511AE2B04EAD9004717BC /* MapPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapPresenter.swift; sourceTree = "<group>"; };
FC2511B02B04EAEC004717BC /* MapModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapModels.swift; sourceTree = "<group>"; };
FC3F3BD72B069EB30080E3A6 /* MapCarouselCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapCarouselCollectionViewCell.swift; sourceTree = "<group>"; };
FC4975862B03432700D8627F /* Pretendard-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-SemiBold.ttf"; sourceTree = "<group>"; };
FC49758A2B03432800D8627F /* Pretendard-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Bold.ttf"; sourceTree = "<group>"; };
FC49758B2B03432800D8627F /* Pretendard-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Regular.ttf"; sourceTree = "<group>"; };
Expand All @@ -157,6 +160,7 @@
FC7E45912AFF747A004F155A /* DummyScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyScene.swift; sourceTree = "<group>"; };
FC7E45932AFF7486004F155A /* DummyDesignSystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyDesignSystem.swift; sourceTree = "<group>"; };
FC7E45952AFF7497004F155A /* DummyExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyExtension.swift; sourceTree = "<group>"; };
FC9BB82B2B094E5500EB72A9 /* UICollectionViewLayout+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewLayout+.swift"; sourceTree = "<group>"; };
FCEE0FF12B036B6000195BBE /* LOButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LOButton.swift; sourceTree = "<group>"; };
FCEE0FF52B03804000195BBE /* LOTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LOTextField.swift; sourceTree = "<group>"; };
FCEE0FF92B03AF8400195BBE /* SignUpViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignUpViewController.swift; path = ../SignUpViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -291,6 +295,7 @@
FC2511AE2B04EAD9004717BC /* MapPresenter.swift */,
FC2511AA2B04EA6B004717BC /* MapConfigurator.swift */,
FC2511B02B04EAEC004717BC /* MapModels.swift */,
FC3F3BD72B069EB30080E3A6 /* MapCarouselCollectionViewCell.swift */,
);
path = MapScene;
sourceTree = "<group>";
Expand Down Expand Up @@ -425,6 +430,7 @@
FC4975982B03439000D8627F /* UIFont+.swift */,
194552012B038B8300299768 /* OSLog+.swift */,
194552292B04883800299768 /* UIView+.swift */,
FC9BB82B2B094E5500EB72A9 /* UICollectionViewLayout+.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -567,6 +573,7 @@
FC68E2A12B023326001AABFF /* EndPoint.swift in Sources */,
FC2511AF2B04EAD9004717BC /* MapPresenter.swift in Sources */,
FC68E2A32B0233BC001AABFF /* NetworkError.swift in Sources */,
FC3F3BD82B069EB30080E3A6 /* MapCarouselCollectionViewCell.swift in Sources */,
FC7E45962AFF7497004F155A /* DummyExtension.swift in Sources */,
194552252B0478B400299768 /* HomeViewController.swift in Sources */,
194552222B0478B400299768 /* HomeWorker.swift in Sources */,
Expand Down Expand Up @@ -602,6 +609,7 @@
19743C052B06940D001E405A /* PlayerView.swift in Sources */,
835A61A02B068115002F22A5 /* PlaybackModels.swift in Sources */,
19C7AFCE2B02410F003B35F2 /* AuthManager.swift in Sources */,
FC9BB82C2B094E5500EB72A9 /* UICollectionViewLayout+.swift in Sources */,
194552232B0478B400299768 /* HomeRouter.swift in Sources */,
835A61922B067FEC002F22A5 /* LOTagStackView.swift in Sources */,
FC7E45902AFF746E004F155A /* DummyWorker.swift in Sources */,
Expand Down
34 changes: 34 additions & 0 deletions iOS/Layover/Layover/Extensions/UICollectionViewLayout+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// UICollectionViewLayout+.swift
// Layover
//
// Created by kong on 2023/11/19.
// Copyright © 2023 CodeBomber. All rights reserved.
//

import UIKit

extension UICollectionViewLayout {
static func createCarouselLayout(groupWidthDimension: CGFloat,
groupHeightDimension: CGFloat,
maximumZoomScale: CGFloat,
minimumZoomScale: CGFloat) -> UICollectionViewLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(groupWidthDimension),
heightDimension: .fractionalHeight(groupHeightDimension))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPagingCentered
section.visibleItemsInvalidationHandler = { items, offset, environment in
let containerWidth = environment.container.contentSize.width
items.forEach { item in
let distanceFromCenter = abs((item.center.x - offset.x) - environment.container.contentSize.width / 2.0)
let scale = max(maximumZoomScale - (distanceFromCenter / containerWidth), minimumZoomScale)
item.transform = CGAffineTransform(scaleX: scale, y: scale)
}
}
return UICollectionViewCompositionalLayout(section: section)
}
Comment on lines +12 to +33
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨네요. 추후 홈 뷰에 쓰인 코드도 이걸 사용하도록 바꿔야겠어요

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// MapCarouselCollectionViewCell.swift
// Layover
//
// Created by kong on 2023/11/17.
// Copyright © 2023 CodeBomber. All rights reserved.
//

import UIKit

final class MapCarouselCollectionViewCell: UICollectionViewCell {

override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
}

required init?(coder: NSCoder) {
super.init(coder: coder)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 backgroundColor = .white들어가야 하는거 아닌가요? 그냥 앱이 종료되는 것만 막는 장치일까요?

}

}
68 changes: 49 additions & 19 deletions iOS/Layover/Layover/Scenes/MapScene/MapViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,15 @@ protocol MapDisplayLogic: AnyObject {

final class MapViewController: BaseViewController {

// MARK: - UI Components

private let mapView: MKMapView = {
let mapView = MKMapView()
mapView.showsUserLocation = true
mapView.setUserTrackingMode(.follow, animated: true)
return mapView
}()

private let currentLocationButton: LOCircleButton = {
let button = LOCircleButton(style: .locate, diameter: 52)
return button
}()

private let uploadButton: LOCircleButton = {
let button = LOCircleButton(style: .add, diameter: 52)
return button
}()

private let searchButton: UIButton = {
var configuration = UIButton.Configuration.filled()
var titleContainer = AttributeContainer()
Expand All @@ -47,7 +39,29 @@ final class MapViewController: BaseViewController {
return button
}()

// MARK: - UI Components
private let currentLocationButton: LOCircleButton = LOCircleButton(style: .locate, diameter: 52)

private let uploadButton: LOCircleButton = LOCircleButton(style: .add, diameter: 52)

private lazy var carouselCollectionView: UICollectionView = {
let layout: UICollectionViewLayout = .createCarouselLayout(groupWidthDimension: 94/375,
groupHeightDimension: 1.0,
maximumZoomScale: 1.0,
minimumZoomScale: 73/94)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = .clear
collectionView.register(MapCarouselCollectionViewCell.self, forCellWithReuseIdentifier: MapCarouselCollectionViewCell.identifier)
return collectionView
}()

private lazy var carouselDatasource = UICollectionViewDiffableDataSource<UUID, Int>(collectionView: carouselCollectionView) { collectionView, indexPath, _ in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MapCarouselCollectionViewCell.identifier,
for: indexPath) as? MapCarouselCollectionViewCell else { return UICollectionViewCell() }
cell.layer.cornerRadius = 10
return cell
}

// MARK: - Properties

var interactor: MapBusinessLogic?

Expand All @@ -57,17 +71,16 @@ final class MapViewController: BaseViewController {
super.viewDidLoad()
MapConfigurator.shared.configure(self)
interactor?.checkLocationAuthorizationStatus()
setCarouselCollectionView()
}

// MARK: - UI + Layout

override func setConstraints() {
view.addSubviews(mapView, searchButton, currentLocationButton, uploadButton)

mapView.translatesAutoresizingMaskIntoConstraints = false
searchButton.translatesAutoresizingMaskIntoConstraints = false
currentLocationButton.translatesAutoresizingMaskIntoConstraints = false
uploadButton.translatesAutoresizingMaskIntoConstraints = false
[mapView, searchButton, currentLocationButton, uploadButton, carouselCollectionView].forEach {
view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
Comment on lines +80 to +83
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

결국 addSubviews는 안 쓰기로 합의가 된 것일까요 ?ㅅ?


NSLayoutConstraint.activate([
mapView.topAnchor.constraint(equalTo: view.topAnchor),
Expand All @@ -79,16 +92,33 @@ final class MapViewController: BaseViewController {
searchButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
searchButton.heightAnchor.constraint(equalToConstant: 42),

uploadButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -15),
uploadButton.bottomAnchor.constraint(equalTo: carouselCollectionView.topAnchor, constant: -15),
uploadButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),

currentLocationButton.bottomAnchor.constraint(equalTo: uploadButton.topAnchor, constant: -10),
currentLocationButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16)
currentLocationButton.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),

carouselCollectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -19),
carouselCollectionView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
carouselCollectionView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
carouselCollectionView.heightAnchor.constraint(equalToConstant: 151)
])
}

private func setCarouselCollectionView() {
carouselCollectionView.dataSource = carouselDatasource
var snapshot = NSDiffableDataSourceSnapshot<UUID, Int>()
snapshot.appendSections([UUID()])
snapshot.appendItems([1, 2, 3, 4, 5, 6, 7, 8, 9])
carouselDatasource.apply(snapshot)
}

}

extension MapViewController: MapDisplayLogic {

}

#Preview {
MapViewController()
}