오늘은 여행 기록 내 지도를 넣어주고, 앨범에 사진을 삽입했을 때 일반적으로 떠있는 앨범이 아니라 살짝 셀을 변형시켜 조금 더 느낌있게 구현하기 위해 커스텀 플로우 레이아웃을 사용해 보았다.
MapKit 사용하기
여행기록을 사용할 때 맵에 지도를 넣어 위치를 나타낼 수 있는 지도를 넣어주기 위해서 맵킷을 사용해 GPS를 기록하려고 맵을 사용하려고 한다.
import UIKit
import MapKit
@objc func mapContainerViewTapped() {
let mapDetailVC = MapDetailViewController()
let navigationController = UINavigationController(rootViewController: mapDetailVC)
navigationController.modalPresentationStyle = .fullScreen
present(navigationController, animated: true, completion: nil)
}
맵컨테이너를 누르면 맵 디테일 VC로 이동하게 된다.
MapDetailViewController 생성하기
먼저 지도 컨테이너 뷰를 누르면 맵이 뜨도록 VC를 만들어 맵을 가득 채우도록 구현하였다.
class MapDetailViewController: UIViewController {
let mapView = MKMapView()
let searchBar = UISearchBar()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupConstraints()
setupSearchBar()
}
func setupUI() {
view.backgroundColor = .white
view.addSubview(mapView)
view.addSubview(searchBar)
}
func setupConstraints() {
mapView.translatesAutoresizingMaskIntoConstraints = false
searchBar.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
mapView.topAnchor.constraint(equalTo: searchBar.bottomAnchor),
mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
mapView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
mapView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
func setupSearchBar() {
searchBar.delegate = self
searchBar.placeholder = "Search for a place or address"
}
}
MKMapView() 를 호출해서 변수에 담아 레이아웃을 설정해주면 손쉽게 구현이 가능해진다.
그리고 맵에 기록을 저장하고 뒤로가서 이전 VC로 돌아가도록 구현했다.
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupConstraints()
setupSearchBar()
setupBackButton() // 새로운 함수 호출
}
func setupBackButton() {
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(backButtonTapped))
navigationItem.leftBarButtonItem = backButton
}
@objc func backButtonTapped() {
dismiss(animated: true, completion: nil)
}
backButton 을 생성해서 뒤로 넘어가 이전 화면으로 돌아갈 수 있도록 구현하였다.
지도에서 보이는 범위를 5km x 5km 를 설정할 수 있도록 로케이션을 넣어주었다.
func setInitialLocation() {
let seoulLocation = CLLocationCoordinate2D(latitude: 37.5665, longitude: 126.9780)
let region = MKCoordinateRegion(center: seoulLocation, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: true)
}
이렇게 넣어주면 특정 범위만 지도에서 보이게 된다.
그리고 특정 지역명을 설정하고 기록할 수 있도록 서치바를 넣어주도록 하자
extension MapDetailViewController: UISearchBarDelegate {
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
let searchRequest = MKLocalSearch.Request()
searchRequest.naturalLanguageQuery = searchBar.text
let activeSearch = MKLocalSearch(request: searchRequest)
activeSearch.start { (response, error) in
if let response = response {
let latitude = response.boundingRegion.center.latitude
let longitude = response.boundingRegion.center.longitude
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let region = MKCoordinateRegion(center: coordinate, latitudinalMeters: 10000, longitudinalMeters: 10000)
self.mapView.setRegion(region, animated: true)
}
}
}
}
서치바 델리게이트를 통해 네비게이션 내 서치바를 넣어 특정 지역명을 검색해 핀을 넣어줄 수 있도록 서치바를 설정해 주었다.
Custom UICollectionViewCell 구현
CollectionView를 활용해 갤러리에 사진을 추가하면 셀에 사진이 추가되도록 구현할 예정이다. 각각 다른 셀 크기를 주고 공백을 줘서 비대칭적으로 구현하였다.
먼저 특정 셀에 특정 값을 주기 위해 코드를 구현하였다.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == galleryCollectionView {
if selectedImages.isEmpty {
return CGSize(width: 173, height: 115)
} else {
switch indexPath.row {
case 0, 3:
return CGSize(width: 173, height: 115)
case 1, 2:
return CGSize(width: 173, height: 223)
default:
return CGSize(width: 173, height: 115)
}
}
} else {
return CGSize(width: 73, height: 73)
}
}
이렇게 각 셀의 인덱스 별로 각 다른 값을 적용해준다.
이 뿐 만 아니라 플로우 레이아웃을 커스텀해 레이아웃을 잡아주도록 하자
class CustomFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let attributes = super.layoutAttributesForElements(in: rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }
attributes?.forEach { layoutAttribute in
if layoutAttribute.representedElementCategory == .cell {
if let newFrame = layoutAttributesForItem(at: layoutAttribute.indexPath)?.frame {
layoutAttribute.frame = newFrame
}
}
}
return attributes
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = super.layoutAttributesForItem(at: indexPath)?.copy() as! UICollectionViewLayoutAttributes
let spacing: CGFloat = 16
let additionalOffset: CGFloat = 50
switch indexPath.item {
case 0:
attributes.frame.origin.y = 0
attributes.frame.origin.x = 0
case 1:
attributes.frame.origin.y = additionalOffset
attributes.frame.origin.x = attributes.frame.width + spacing
case 2:
if let firstItemAttributes = layoutAttributesForItem(at: IndexPath(item: 0, section: indexPath.section)) {
attributes.frame.origin.y = firstItemAttributes.frame.maxY + spacing
attributes.frame.origin.x = 0
}
case 3:
if let secondItemAttributes = layoutAttributesForItem(at: IndexPath(item: 1, section: indexPath.section)) {
attributes.frame.origin.y = secondItemAttributes.frame.maxY + spacing
attributes.frame.origin.x = secondItemAttributes.frame.minX
}
default:
break
}
return attributes
}
}
별도의 커스텀 플로우레이아웃을 설정해 사이 간격과 x y 값을 설정해 넣어주었다.
func createCollectionViewFlowLayout(for scrollDirection: UICollectionView.ScrollDirection) -> UICollectionViewFlowLayout {
let layout = CustomFlowLayout()
layout.scrollDirection = scrollDirection
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 5
layout.estimatedItemSize = .zero
return layout
}
커스텀으로 설정한 플로우 레이아웃을 컬렉션 뷰 레이아웃에 넣어주면 커스텀 된 뷰를 사용가능하다 😀
오늘은 여기까지!
'◽️ Programming > T I L' 카테고리의 다른 글
[Project 일지] 여행 기록 앱 만들기 (4) - scrollViewDidScroll, SegmentControl (0) | 2024.06.05 |
---|---|
[Project 일지] 여행 기록 앱 만들기 (3) - isExpanded , isUserInteractionEnabled (0) | 2024.06.03 |
[Project 일지] 여행 기록 앱 만들기 (1) - ScrollView , CollectionCustomView (2) | 2024.05.29 |
[Project 일지] 단어장 앱 만들기 (6) (0) | 2024.05.20 |
[Project 일지] 단어장 앱 만들기 (5) (0) | 2024.05.19 |