2024.05.31 - [◽️ Programming/T I L] - [Project 일지] 여행 기록 앱 만들기 (2) - MapKit , CustomFlowLayout
세부 페이지를 만들면서 앨범과 지도에 대한 물리적인 한계로 인해 원하던 구현이 어려울 것으로 판단되어 팀원들과 상의한 끝에 상당부분 많은 내용을 변경하고 input을 넣을 수 있는 페이지를 추가하여 구현하기로 했다.
코드로 UI구성을 이번 기회에 엄청 많이 해보면서 오토레이아웃을 잡는 과정에 대해서 더욱 숙련할 수 있는 과정인 것 같다.
먼저 새롭게 구성된 인풋화면 구성을 보면 이전에 완성된 페이지 내 정보를 넣어줄 수 있도록 애니메이션과 스크롤로 움직이는 부분을 최소화 하고 이용자 편의에 맞춰 여행 기록에 초점을 맞춰 사용할 수 있도록 구현하였다.
일단 오늘은 우선적으로 UI구성에 주력을 잡았기 때문에 별도 코드는 적지 않겠지만 데이터를 전달하는 과정과 UI구성 중 트러블 슈팅의 한가지 내용이 확인되어 해당 내용을 작성해 두고자 한다.
데이터 전달 방식 구현
먼저 위에 사진처럼 인풋으로 데이터를 넣어 준 상황에서 해당 내용을 우측 사단의 Done 버튼을 누르면 detailVC로 전달할 수 있도록 구현하였다.
@objc func doneButtonTapped() {
let detailVC = DetailViewController()
//detailVC.publicSwitchIsOn = publicSwitch.isOn
detailVC.dateStartLabel.text = startDateButton.title(for: .normal)
detailVC.dateEndLabel.text = endDateButton.title(for: .normal)
detailVC.mainTitleLabel.text = mainTextField.text
detailVC.subTextLabel.text = subTextField.text
detailVC.selectedImages = selectedImages
detailVC.selectedFriends = selectedFriends
navigationController?.pushViewController(detailVC, animated: true)
}
그 다음 DetailVC로 넘어와 기존 앨범과 지도의 물리적 한계를 극복하기 위해 UI 구현을 변경하였다.
SegmentControl
세그먼트 컨트롤러를 활용해 앨범과 지도 기능을 선택해서 확인 할 수 있도록 할 수 있다.
func setupSegmentControl() {
segmentControl.addTarget(self, action: #selector(segmentChanged(_:)), for: .valueChanged)
}
@objc func segmentChanged(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0 {
mapView.isHidden = false
galleryCollectionView.isHidden = false
albumImageView.isHidden = true
mapAllButton.isHidden = false
albumAllButton.isHidden = true
} else {
mapView.isHidden = true
galleryCollectionView.isHidden = false
albumImageView.isHidden = false
mapAllButton.isHidden = true
albumAllButton.isHidden = false
if !selectedImages.isEmpty {
albumImageView.image = selectedImages[0]
}
}
}
세그먼트 컨트롤러의 벨류체인지에 작동하는 메서드를 이런식으로 구현해주면 원하는 내용을 숨기고 보여주기가 가능하다.
Codebase 장점
코드로 UI를 구현하는게 좋은 점이 이럴때 참 좋은 것 같다 구성이 많이 바뀌어 스토리보드였다면 새로 시작하는게 나을정도 였지만 스크롤 구현 이라던지 재사용이 가능하며 오토레이아웃만 변경하여 생각보다 손 쉽게 구조 변경이 가능하였다.
extension DetailViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.scrollView {
let offset = scrollView.contentOffset.y
if let overlayView = backgroundImageView.viewWithTag(999) {
overlayView.frame = backgroundImageView.bounds
}
if offset > 0 {
UIView.animate(withDuration: 0.3) {
self.locationStackView.axis = .horizontal
self.locationStackView.spacing = 10
self.locationStackView.alignment = .center
self.locationLabel.font = UIFont.systemFont(ofSize: 20)
self.dateStackView.isHidden = true
self.locationStackView.snp.remakeConstraints {
$0.top.equalTo(self.view.safeAreaLayoutGuide).offset(20)
$0.centerX.equalToSuperview()
}
self.scrollView.layer.cornerRadius = 40
self.view.clipsToBounds = true
self.scrollView.snp.remakeConstraints {
$0.top.equalTo(self.backgroundImageView.snp.bottom).offset(-40)
$0.leading.trailing.equalTo(self.view.safeAreaLayoutGuide)
$0.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
}
self.contentView.snp.remakeConstraints {
$0.edges.equalTo(self.scrollView.contentLayoutGuide)
$0.width.equalTo(self.scrollView.frameLayoutGuide)
$0.bottom.equalTo(self.bottomLogo.snp.bottom).offset(70)
}
self.backgroundImageView.snp.updateConstraints {
$0.height.equalTo(150)
}
self.view.layoutIfNeeded()
}
} else {
UIView.animate(withDuration: 0.3) {
self.locationStackView.axis = .vertical
self.locationStackView.spacing = 10
self.locationStackView.alignment = .leading
self.locationLabel.font = UIFont.systemFont(ofSize: 40)
self.dateStackView.isHidden = false
self.locationStackView.snp.remakeConstraints {
$0.bottom.equalTo(self.scrollView.snp.top).offset(-32)
$0.leading.equalTo(self.topContentView).inset(38)
}
self.scrollView.snp.remakeConstraints {
$0.top.equalTo(self.backgroundImageView.snp.bottom).offset(-40)
$0.leading.trailing.equalTo(self.view.safeAreaLayoutGuide)
$0.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
}
self.contentView.snp.remakeConstraints {
$0.edges.equalTo(self.scrollView.contentLayoutGuide)
$0.width.equalTo(self.scrollView.frameLayoutGuide)
$0.bottom.equalTo(self.bottomLogo.snp.bottom).offset(70)
}
self.backgroundImageView.snp.updateConstraints {
$0.height.equalTo(457)
}
self.view.layoutIfNeeded()
}
}
}
}
func applyDarkOverlayToBackgroundImage() {
backgroundImageView.subviews.forEach { subview in
if subview.tag == 999 {
subview.removeFromSuperview()
}
}
let overlayView = UIView(frame: backgroundImageView.bounds)
overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.1)
overlayView.tag = 999
backgroundImageView.addSubview(overlayView)
backgroundImageView.bringSubviewToFront(topContentView)
self.view.layoutIfNeeded()
}
}
이런식으로 올라가고 내려가는 높이정도만 수정하면 바로 사용이 가능하다.
Scroll event issue
여기서 문제점이 스크롤뷰를 통해서 뷰를 올리고 컬렉션 뷰를 가로로 스크롤하면 스크롤 이벤트를 스크롤뷰와 컬렉션 뷰가 동시에 작동시켜 컬렉션 뷰를 스크롤 하면 스크롤뷰가 원래의 스크롤로 돌아가 버리는 문제가 발생하였다.
여러가지 방법을 찾아 본 결과, 스크롤 이벤트가 스크롤 뷰와 컬렉션 뷰 동시에 작동되고 있다는 점을 알게 되어 위아래로 스크롤 되는 이 이벤트는 스크롤 뷰의 offset 값에 의해 움직인다는 점을 명시해주면 되지 않을까 하는 생각이 들어 해당 내용으로 적용했더니 문제가 해결되었다!
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView == self.scrollView {
let offset = scrollView.contentOffset.y
if let overlayView = backgroundImageView.viewWithTag(999) {
overlayView.frame = backgroundImageView.bounds
}
if offset > 0 {
UIView.animate(withDuration: 0.3) {
self.locationStackView.axis = .horizontal
self.locationStackView.spacing = 10
self.locationStackView.alignment = .center
self.locationLabel.font = UIFont.systemFont(ofSize: 20)
self.dateStackView.isHidden = true
self.locationStackView.snp.remakeConstraints {
$0.top.equalTo(self.view.safeAreaLayoutGuide).offset(20)
$0.centerX.equalToSuperview()
}
먼저 적용된 코드를 자세하게 살펴보면 offset에 크기에 따라 상하 스크롤이 움직이고 있기 때문에 해당 내용을 scrollview.contentOffset.y의 값으로 설정해주니 위 아래 스크롤 이후 컬렉션 뷰 가로 스크롤을 해도 움직이던 스크롤이 움직이지 않게 되어 문제가 해결되었다!
스크롤도 각각의 이벤트가 있어 특정 스크롤 구간에 어떤 스크롤 이벤트를 적용할지 명시해야한다는 점을 알 수 있었다.
'◽️ Programming > T I L' 카테고리의 다른 글
[Project 일지] 여행 기록 앱 만들기 (6) - Mate 추가 (0) | 2024.06.13 |
---|---|
[Project 일지] 여행 기록 앱 만들기 (5) - sendSubviewToBack , 비동기 처리 (1) | 2024.06.07 |
[Project 일지] 여행 기록 앱 만들기 (3) - isExpanded , isUserInteractionEnabled (0) | 2024.06.03 |
[Project 일지] 여행 기록 앱 만들기 (2) - MapKit , CustomFlowLayout (0) | 2024.05.31 |
[Project 일지] 여행 기록 앱 만들기 (1) - ScrollView , CollectionCustomView (2) | 2024.05.29 |