From daaa336657fdf68131bb85717a15466f8e433413 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 2 Jan 2023 16:20:25 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[Feat]=20#13=20-=20=EC=A7=80=EB=8F=84=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS.xcodeproj/project.pbxproj | 24 +++++++ .../Global/Extension/UIKit+/UIImage+.swift | 9 +++ .../Global/Supports/SceneDelegate.swift | 2 +- .../UIComponents/MapView/RNMapView.swift | 8 +++ .../UIComponents/MapView/RNMarker.swift | 38 +++++++++++ .../UIComponents/MapView/RNStartMarker.swift | 66 +++++++++++++++++++ .../Global/Utils/convertLocationObject.swift | 29 ++++++++ .../VC/CourseDrawingHomeVC.swift | 56 ++++++++++------ 8 files changed, 211 insertions(+), 21 deletions(-) create mode 100644 Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift create mode 100644 Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMarker.swift create mode 100644 Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNStartMarker.swift create mode 100644 Runnect-iOS/Runnect-iOS/Global/Utils/convertLocationObject.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index daad92f4..b67b27cf 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -64,6 +64,10 @@ CE665615295D989A00C64E12 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = CE665614295D989A00C64E12 /* .swiftlint.yml */; }; CEC2A6852961F92C00160BF7 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6842961F92C00160BF7 /* CustomButton.swift */; }; CEC2A68729629B9B00160BF7 /* SignInVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68629629B9B00160BF7 /* SignInVC.swift */; }; + CEC2A68A2962ADCD00160BF7 /* RNMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6892962ADCD00160BF7 /* RNMapView.swift */; }; + CEC2A68C2962AE1B00160BF7 /* RNStartMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68B2962AE1B00160BF7 /* RNStartMarker.swift */; }; + CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */; }; + CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */; }; CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */; }; CEEC6B3C2961C51A00D00E1E /* CourseStorageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */; }; CEEC6B3E2961C53700D00E1E /* CourseDiscoveryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */; }; @@ -138,6 +142,10 @@ CE665614295D989A00C64E12 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; CEC2A6842961F92C00160BF7 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = ""; }; CEC2A68629629B9B00160BF7 /* SignInVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInVC.swift; sourceTree = ""; }; + CEC2A6892962ADCD00160BF7 /* RNMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNMapView.swift; sourceTree = ""; }; + CEC2A68B2962AE1B00160BF7 /* RNStartMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNStartMarker.swift; sourceTree = ""; }; + CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNMarker.swift; sourceTree = ""; }; + CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = convertLocationObject.swift; sourceTree = ""; }; CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDrawingHomeVC.swift; sourceTree = ""; }; CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorageVC.swift; sourceTree = ""; }; CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryVC.swift; sourceTree = ""; }; @@ -466,6 +474,7 @@ CE58759D29601476005D967E /* LoadingIndicator.swift */, CE58759F29601500005D967E /* Toast.swift */, CE6655C9295D84DD00C64E12 /* UserDefaultKeyList.swift */, + CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */, ); path = Utils; sourceTree = ""; @@ -513,6 +522,7 @@ CE6655B6295D803C00C64E12 /* UIComponents */ = { isa = PBXGroup; children = ( + CEC2A6882962ADB900160BF7 /* MapView */, CEEC6B4A2961D89700D00E1E /* CustomNavigationBar.swift */, CEC2A6842961F92C00160BF7 /* CustomButton.swift */, ); @@ -593,6 +603,16 @@ path = "UIKit+"; sourceTree = ""; }; + CEC2A6882962ADB900160BF7 /* MapView */ = { + isa = PBXGroup; + children = ( + CEC2A6892962ADCD00160BF7 /* RNMapView.swift */, + CEC2A68B2962AE1B00160BF7 /* RNStartMarker.swift */, + CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */, + ); + path = MapView; + sourceTree = ""; + }; CEEC6B472961C5CA00D00E1E /* VC */ = { isa = PBXGroup; children = ( @@ -765,6 +785,7 @@ CE6655E8295D889600C64E12 /* UISwitch+.swift in Sources */, CE5875A029601500005D967E /* Toast.swift in Sources */, CE6655F6295D90B600C64E12 /* addToolBar.swift in Sources */, + CEC2A68A2962ADCD00160BF7 /* RNMapView.swift in Sources */, CE6655F0295D891B00C64E12 /* UITextView+.swift in Sources */, CE6655EE295D88E600C64E12 /* UITextField+.swift in Sources */, CE6655F8295D90CF00C64E12 /* adjusted+.swift in Sources */, @@ -776,6 +797,7 @@ CE6655D4295D865B00C64E12 /* Publisher+UIControl.swift in Sources */, CE6655EC295D88D000C64E12 /* UITableView+.swift in Sources */, CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */, + CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */, CEC2A6852961F92C00160BF7 /* CustomButton.swift in Sources */, CE66560C295D928300C64E12 /* setRootViewController.swift in Sources */, CE6655D9295D871B00C64E12 /* URL+.swift in Sources */, @@ -785,9 +807,11 @@ CE665612295D92E400C64E12 /* UserDefaultWrapper.swift in Sources */, CE665610295D92C200C64E12 /* setTextLineHeight.swift in Sources */, CE6655E2295D87EB00C64E12 /* UIImage+.swift in Sources */, + CEC2A68C2962AE1B00160BF7 /* RNStartMarker.swift in Sources */, CE5875A4296015D2005D967E /* Encodable+.swift in Sources */, CEEC6B4B2961D89700D00E1E /* CustomNavigationBar.swift in Sources */, CE17F02D2961BBA100E1DED0 /* ColorLiterals.swift in Sources */, + CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */, CE6655D2295D862A00C64E12 /* Publisher+Driver.swift in Sources */, CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, CE6655CA295D84DD00C64E12 /* UserDefaultKeyList.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Extension/UIKit+/UIImage+.swift b/Runnect-iOS/Runnect-iOS/Global/Extension/UIKit+/UIImage+.swift index 50a36e0a..86abf3bd 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Extension/UIKit+/UIImage+.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Extension/UIKit+/UIImage+.swift @@ -33,4 +33,13 @@ extension UIImage { } return renderImage } + + /// UIView를 image로 변환 + convenience init(view: UIView) { + UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0) + view.drawHierarchy(in: view.bounds, afterScreenUpdates: false) + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + self.init(cgImage: (image?.cgImage)!) + } } diff --git a/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift b/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift index ac34efc3..b1a5c3a4 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Supports/SceneDelegate.swift @@ -16,7 +16,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) - window.rootViewController = UINavigationController(rootViewController: SplashVC()) + window.rootViewController = TabBarController() self.window = window window.makeKeyAndVisible() } diff --git a/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift new file mode 100644 index 00000000..7ec98437 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift @@ -0,0 +1,8 @@ +// +// RNMapView.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/02. +// + +import Foundation diff --git a/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMarker.swift b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMarker.swift new file mode 100644 index 00000000..386b0f41 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMarker.swift @@ -0,0 +1,38 @@ +// +// RNMarker.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/02. +// + +import UIKit + +import NMapsMap +import SnapKit +import Then + +final class RNMarker: NMFMarker { + + // MARK: - initialization + + override init() { + super.init() + setUI() + } +} + +// MARK: - UI & Layout + +extension RNMarker { + private func setUI() { + let image = NMFOverlayImage(image: ImageLiterals.icMapPoint) + self.iconImage = image + + self.width = CGFloat(NMF_MARKER_SIZE_AUTO) + self.height = CGFloat(NMF_MARKER_SIZE_AUTO) + + self.anchor = CGPoint(x: 0.5, y: 0.5) + + self.iconPerspectiveEnabled = true + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNStartMarker.swift b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNStartMarker.swift new file mode 100644 index 00000000..a54503a9 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNStartMarker.swift @@ -0,0 +1,66 @@ +// +// RNStartMarker.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/02. +// + +import UIKit + +import NMapsMap +import SnapKit +import Then + +final class RNStartMarker: NMFMarker { + + // MARK: - UI & Layout + + let startInfoWindow = NMFInfoWindow() + + // MARK: - initialization + + override init() { + super.init() + setUI() + setInfoWindow() + } +} + +// MARK: - UI & Layout + +extension RNStartMarker { + private func setUI() { + let image = NMFOverlayImage(image: ImageLiterals.icMapDeparture) + self.iconImage = image + + self.width = CGFloat(NMF_MARKER_SIZE_AUTO) + self.height = CGFloat(NMF_MARKER_SIZE_AUTO) + + self.anchor = CGPoint(x: 0.5, y: 0.5) + + self.iconPerspectiveEnabled = true + } + + private func setInfoWindow() { + startInfoWindow.dataSource = self + } + + func showInfoWindow() { + startInfoWindow.open(with: self) + } + + func hideInfoWindow() { + startInfoWindow.close() + } +} + +// MARK: - NMFOverlayImageDataSource + +extension RNStartMarker: NMFOverlayImageDataSource { + func view(with overlay: NMFOverlay) -> UIView { + // 마커 위에 보여줄 InfoView 이미지 리턴 + let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 58, height: 34)) + imageView.image = ImageLiterals.icMapDeparture + return imageView + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Utils/convertLocationObject.swift b/Runnect-iOS/Runnect-iOS/Global/Utils/convertLocationObject.swift new file mode 100644 index 00000000..cc95fe70 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Utils/convertLocationObject.swift @@ -0,0 +1,29 @@ +// +// convertLocationObject.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/02. +// + +import Foundation +import CoreLocation + +import NMapsMap + +extension CLLocationCoordinate2D? { + func toNMGLatLng() -> NMGLatLng { + return NMGLatLng(lat: self?.latitude ?? 37.52901832956373, lng: self?.longitude ?? 126.9136196847032) + } +} + +extension CLLocationCoordinate2D { + func toNMGLatLng() -> NMGLatLng { + return NMGLatLng(lat: self.latitude, lng: self.longitude) + } +} + +extension NMGLatLng { + func toCLLocation() -> CLLocation { + return CLLocation(latitude: lat, longitude: lng) + } +} diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift index 69bedd9f..0e15a1cc 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift @@ -7,34 +7,50 @@ import UIKit -final class CourseDrawingHomeVC: UIViewController, CustomNavigationBarDelegate { - lazy var naviBar = CustomNavigationBar(self, type: .title).setTitle("보관함") -// lazy var naviBar = CustomNavigationBar(self, type: .titleWithLeftButton) -// lazy var naviBar = CustomNavigationBar(self, type: .titleWithLeftButton).setTitle("목표 보상") -// lazy var naviBar = CustomNavigationBar(self, type: .search).showKeyboard().setTextFieldPlaceholder(placeholder: "출발지 검색") +final class CourseDrawingHomeVC: UIViewController { - let button = CustomButton(title: "코스 그리기") + // MARK: - Properties + + private lazy var tabBarHeight = self.tabBarController?.tabBar.frame.size.height ?? 49 + + // MARK: - UI Components + + private lazy var mapView = RNMapView() + .setPositionMode(mode: .normal) + .makeContentPadding(padding: UIEdgeInsets(top: -calculateTopInset(), left: 0, bottom: tabBarHeight, right: 0)) + .moveToUserLocation() + .showLocationButton(toShow: true) + + private let drawCourseButton = CustomButton(title: "코스 그리기") + + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .white - - naviBar.delegate = self - - view.addSubviews(naviBar, button) + self.setUI() + self.setLayout() + } +} + +// MARK: - UI & Layout + +extension CourseDrawingHomeVC { + private func setUI() { + view.backgroundColor = .w1 + } + + private func setLayout() { + view.addSubviews(mapView, drawCourseButton) - naviBar.snp.makeConstraints { make in - make.leading.top.trailing.equalTo(view.safeAreaLayoutGuide) - make.height.equalTo(48) + mapView.snp.makeConstraints { make in + make.top.bottom.equalToSuperview() + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) } - button.snp.makeConstraints { make in - make.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide).inset(20) + drawCourseButton.snp.makeConstraints { make in + make.leading.trailing.equalTo(view.safeAreaLayoutGuide).inset(75) + make.bottom.equalTo(view.safeAreaLayoutGuide).inset(24) make.height.equalTo(44) } } - - func searchButtonDidTap(text: String) { - print(text) - } } From 571611ad5a3c6b4bd5d98fbc7583b4737e0d14d3 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 2 Jan 2023 16:21:28 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[Feat]=20#13=20-=20NaverMap=EC=9D=84=20?= =?UTF-8?q?=EA=B0=90=EC=8B=BC=20RNMapView=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UIComponents/MapView/RNMapView.swift | 350 +++++++++++++++++- 1 file changed, 349 insertions(+), 1 deletion(-) diff --git a/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift index 7ec98437..b65e8360 100644 --- a/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift +++ b/Runnect-iOS/Runnect-iOS/Global/UIComponents/MapView/RNMapView.swift @@ -4,5 +4,353 @@ // // Created by sejin on 2023/01/02. // +import UIKit +import CoreLocation +import Combine -import Foundation +import NMapsMap +import SnapKit +import Then + +final class RNMapView: UIView { + + // MARK: - Properties + + @Published var pathDistance: Double = 0 + let pathImage = PassthroughSubject() + var cancelBag = Set() + + let locationManager = CLLocationManager() + private var isDrawMode: Bool = false + private var markers = [RNMarker]() { + didSet { + self.makePath() + self.setUndoButton() + } + } + /// startMarker를 포함한 모든 마커들의 위치 정보 + private var markersLatLngs: [NMGLatLng] { + [self.startMarker.position] + self.markers.map { $0.position } + } + private var bottomPadding: CGFloat = 0 + + // MARK: - UI Components + + let map = NMFNaverMapView() + private var startMarker = RNStartMarker() + private let pathOverlay = NMFPath() + private let locationButton = UIButton(type: .custom) + private let undoButton = UIButton(type: .custom) + + // MARK: - initialization + + public init() { + super.init(frame: .zero) + setUI() + setLayout() + setDelegate() + setMap() + getLocationAuth() + setPathOverlay() + } + + override init(frame: CGRect) { + super.init(frame: frame) + setUI() + setLayout() + setDelegate() + setMap() + getLocationAuth() + setPathOverlay() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Methods + +extension RNMapView { + + /// isDrawMode (편집 모드) 설정 + @discardableResult + func setDrawMode(to isDrawMode: Bool) -> Self { + self.isDrawMode = isDrawMode + return self + } + + /// 카메라가 따라가는 mode 설정 + @discardableResult + func setPositionMode(mode: NMFMyPositionMode) -> Self { + map.mapView.positionMode = mode + return self + } + + /// 지정 위치에 startMarker와 출발 infoWindow 생성 (기존의 startMarker는 제거) + @discardableResult + func makeStartMarker(at location: NMGLatLng) -> Self { + self.startMarker.position = location + self.startMarker.mapView = self.map.mapView + self.startMarker.showInfoWindow() + return self + } + + /// 사용자 위치에 startMarker와 출발 infoWindow 생성 (기존의 startMarker는 제거) + @discardableResult + func makeStartMarkerAtUserLocation() -> Self { + self.startMarker.position = getUserLocation() + self.startMarker.mapView = self.map.mapView + self.startMarker.showInfoWindow() + return self + } + + /// 지정 위치에 마커 생성 + @discardableResult + func makeMarker(at location: NMGLatLng) -> Self { + let marker = RNMarker() + marker.position = location + marker.mapView = self.map.mapView + addDistance(with: location) + self.markers.append(marker) + return self + } + + /// NMGLatLng 어레이를 받아서 모든 위치에 마커 생성 + @discardableResult + func makeMarkers(at locations: [NMGLatLng]) -> Self { + locations.forEach { location in + makeMarker(at: location) + } + return self + } + + /// NMGLatLng 어레이를 받아서 첫 위치를 startMarker로 설정하고 나머지를 일반 마커로 생성 + @discardableResult + func makeMarkersWithStartMarker(at locations: [NMGLatLng]) -> Self { + if locations.count < 2 { return self } + makeStartMarker(at: locations[0]) + locations[1...].forEach { location in + makeMarker(at: location) + } + return self + } + + /// 사용자 위치로 카메라 이동 + @discardableResult + func moveToUserLocation() -> Self { + let userLatLng = getUserLocation() + let cameraUpdate = NMFCameraUpdate(scrollTo: userLatLng) + + DispatchQueue.main.async { [self] in + cameraUpdate.animation = .easeIn + self.map.mapView.moveCamera(cameraUpdate) + } + return self + } + + /// 저장된 위치들로 경로선 그리기 + @discardableResult + func makePath() -> Self { + if self.markersLatLngs.count == 1 { + self.pathOverlay.mapView = nil + return self + } + pathOverlay.path = NMGLineString(points: self.markersLatLngs) + pathOverlay.mapView = map.mapView + return self + } + + /// locationButton 설정 + @discardableResult + func showLocationButton(toShow: Bool) -> Self { + self.locationButton.isHidden = !toShow + return self + } + + /// undoButton 설정 + @discardableResult + func showUndoButton(toShow: Bool) -> Self { + self.undoButton.isHidden = !toShow + return self + } + + /// 지도에 ContentPadding을 지정하여 중심 위치가 변경되게 설정 + @discardableResult + func makeContentPadding(padding: UIEdgeInsets) -> Self { + map.mapView.contentInset = padding + self.bottomPadding = padding.bottom + updateSubviewsConstraints() + return self + } + + /// 현재 존재하는 Marker들 위치 리턴 + func getMarkersLatLng() -> [NMGLatLng] { + return self.markersLatLngs + } + + /// 사용자 위치 가져오기 + func getUserLocation() -> NMGLatLng { + let userLocation = locationManager.location?.coordinate + let userLatLng = userLocation.toNMGLatLng() + return userLatLng + } + + /// 경로 총 거리 가져오기 + func getPathDistance() -> Double { + return pathDistance + } + + /// 경로 뷰를 UIImage로 변환하여 pathImage에 send + func getPathImage() { + let bounds = makeMBR() + let dummyMap = RNMapView(frame: CGRect(x: 50, y: 50, width: 300, height: 250)) + .makeMarkersWithStartMarker(at: self.markersLatLngs) + addSubview(dummyMap) + sendSubviewToBack(dummyMap) + let cameraUpdate = NMFCameraUpdate(fit: bounds, padding: 150) + cameraUpdate.animation = .none + dummyMap.map.mapView.moveCamera(cameraUpdate) + + DispatchQueue.main.asyncAfter(deadline: .now()+1) { + self.pathImage.send(UIImage(view: dummyMap.map.mapView)) + } + } + + // 바운더리(MBR) 생성 + func makeMBR() -> NMGLatLngBounds { + var latitudes = [Double]() + var longitudes = [Double]() + self.markersLatLngs.forEach { latLng in + latitudes.append(latLng.lat) + longitudes.append(latLng.lng) + } + + let southWest = NMGLatLng(lat: latitudes.min() ?? 0, lng: longitudes.min() ?? 0) + let northEast = NMGLatLng(lat: latitudes.max() ?? 0, lng: longitudes.max() ?? 0) + return NMGLatLngBounds(southWest: southWest, northEast: northEast) + } + + // 두 지점 사이의 거리(m) 추가 + private func addDistance(with newLocation: NMGLatLng) { + let lastCLLoc = markersLatLngs.last?.toCLLocation() + let newCLLoc = newLocation.toCLLocation() + guard let distance = lastCLLoc?.distance(from: newCLLoc) else { return } + pathDistance += distance + } + + // 마지막 지점까지의 거리(m) 제거 + private func substractDistance(with targetLocation: NMGLatLng) { + let lastCLLoc = markersLatLngs.last?.toCLLocation() + let targetCLLoc = targetLocation.toCLLocation() + guard let distance = lastCLLoc?.distance(from: targetCLLoc) else { return } + pathDistance -= distance + if pathDistance < 1 { pathDistance = 0 } + } + + private func setMap() { + // 카메라 대상 지점을 한반도로 고정 + map.mapView.extent = NMGLatLngBounds(southWestLat: 31.43, southWestLng: 122.37, northEastLat: 44.35, northEastLng: 132) + map.showLocationButton = false + map.showScaleBar = false + + map.mapView.logoAlign = .leftTop + } + + private func getLocationAuth() { + DispatchQueue.global().async { [self] in + if CLLocationManager.locationServicesEnabled() { + print("위치 상태 On 상태") + self.locationManager.startUpdatingLocation() + } else { + print("위치 상태 Off 상태") + } + } + } + + private func setDelegate() { + locationManager.delegate = self + locationManager.desiredAccuracy = CLLocationAccuracy.greatestFiniteMagnitude + locationManager.requestWhenInUseAuthorization() + + map.mapView.addCameraDelegate(delegate: self) + map.mapView.touchDelegate = self + } + + private func setPathOverlay() { + pathOverlay.width = 3 + pathOverlay.outlineWidth = 0 + pathOverlay.color = .purple + } + + private func setUndoButton() { + self.undoButton.isEnabled = (markers.count >= 1) + } +} + +// MARK: - UI & Layout + +extension RNMapView { + private func setUI() { + self.backgroundColor = .white + self.locationButton.setImage(ImageLiterals.icMapLocation, for: .normal) + self.locationButton.isHidden = true + self.locationButton.addTarget(self, action: #selector(locationButtonDidTap), for: .touchUpInside) + + self.undoButton.setImage(ImageLiterals.icCancel, for: .normal) + self.undoButton.isHidden = true + self.undoButton.addTarget(self, action: #selector(undoButtonDidTap), for: .touchUpInside) + } + + private func setLayout() { + addSubviews(map, locationButton, undoButton) + + map.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + locationButton.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(98+bottomPadding) + make.trailing.equalToSuperview().inset(24) + } + + undoButton.snp.makeConstraints { make in + make.bottom.equalToSuperview().inset(98+bottomPadding) + make.trailing.equalToSuperview().inset(24) + } + } + + private func updateSubviewsConstraints() { + [locationButton, undoButton].forEach { view in + view.snp.updateConstraints { make in + make.bottom.equalToSuperview().inset(98+bottomPadding) + } + } + } +} + +// MARK: - @objc Function + +extension RNMapView { + @objc func locationButtonDidTap() { + self.setPositionMode(mode: .direction) + } + + @objc func undoButtonDidTap() { + guard let lastMarker = self.markers.popLast() else { return } + substractDistance(with: lastMarker.position) + lastMarker.mapView = nil + } +} + +// MARK: - NMFMapViewCameraDelegate, NMFMapViewTouchDelegate + +extension RNMapView: NMFMapViewCameraDelegate, NMFMapViewTouchDelegate { + // 지도 탭 이벤트 + func mapView(_ mapView: NMFMapView, didTapMap latlng: NMGLatLng, point: CGPoint) { + guard isDrawMode else { return } + self.makeMarker(at: latlng) + } +} + +extension RNMapView: CLLocationManagerDelegate {} From 5169afa91899b804dc1ceddb4253883848759c8a Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 2 Jan 2023 16:48:01 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[Feat]=20#13=20-=20DepartureSearchVC=20?= =?UTF-8?q?=EA=B8=B0=EC=B4=88=20UI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS.xcodeproj/project.pbxproj | 4 + .../VC/CourseDrawingHomeVC.swift | 17 ++++ .../CourseDrawing/VC/DepartureSearchVC.swift | 96 +++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index b67b27cf..71603320 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -68,6 +68,7 @@ CEC2A68C2962AE1B00160BF7 /* RNStartMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68B2962AE1B00160BF7 /* RNStartMarker.swift */; }; CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */; }; CEC2A6902962B06C00160BF7 /* convertLocationObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */; }; + CEC2A6922962BE2900160BF7 /* DepartureSearchVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */; }; CEEC6B3A2961C4F300D00E1E /* CourseDrawingHomeVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */; }; CEEC6B3C2961C51A00D00E1E /* CourseStorageVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */; }; CEEC6B3E2961C53700D00E1E /* CourseDiscoveryVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */; }; @@ -146,6 +147,7 @@ CEC2A68B2962AE1B00160BF7 /* RNStartMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNStartMarker.swift; sourceTree = ""; }; CEC2A68D2962AF2C00160BF7 /* RNMarker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNMarker.swift; sourceTree = ""; }; CEC2A68F2962B06C00160BF7 /* convertLocationObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = convertLocationObject.swift; sourceTree = ""; }; + CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DepartureSearchVC.swift; sourceTree = ""; }; CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDrawingHomeVC.swift; sourceTree = ""; }; CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorageVC.swift; sourceTree = ""; }; CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryVC.swift; sourceTree = ""; }; @@ -258,6 +260,7 @@ isa = PBXGroup; children = ( CEEC6B392961C4F300D00E1E /* CourseDrawingHomeVC.swift */, + CEC2A6912962BE2900160BF7 /* DepartureSearchVC.swift */, ); path = VC; sourceTree = ""; @@ -787,6 +790,7 @@ CE6655F6295D90B600C64E12 /* addToolBar.swift in Sources */, CEC2A68A2962ADCD00160BF7 /* RNMapView.swift in Sources */, CE6655F0295D891B00C64E12 /* UITextView+.swift in Sources */, + CEC2A6922962BE2900160BF7 /* DepartureSearchVC.swift in Sources */, CE6655EE295D88E600C64E12 /* UITextField+.swift in Sources */, CE6655F8295D90CF00C64E12 /* adjusted+.swift in Sources */, CE4545CB295D7AF4003201E1 /* SceneDelegate.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift index 0e15a1cc..05a8d25e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/CourseDrawingHomeVC.swift @@ -29,6 +29,23 @@ final class CourseDrawingHomeVC: UIViewController { super.viewDidLoad() self.setUI() self.setLayout() + self.setAddTarget() + } +} + +// MARK: - Methods + +extension CourseDrawingHomeVC { + private func setAddTarget() { + drawCourseButton.addTarget(self, action: #selector(pushToDepartureSearchVC), for: .touchUpInside) + } +} + +// MARK: - @objc Function +extension CourseDrawingHomeVC { + @objc private func pushToDepartureSearchVC() { + let departureSearchVC = DepartureSearchVC() + self.navigationController?.pushViewController(departureSearchVC, animated: true) } } diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift new file mode 100644 index 00000000..4c919df2 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift @@ -0,0 +1,96 @@ +// +// DepartureSearchVC.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/02. +// + +import UIKit + +final class DepartureSearchVC: UIViewController { + + // MARK: - UI Components + + private lazy var naviBar = CustomNavigationBar(self, type: .search).setTextFieldPlaceholder(placeholder: "지역과 키워드 위주로 검색해보세요") + + private let dividerView = UIView().then { + $0.backgroundColor = .g4 + } + + private let locationTableView = UITableView(frame: .zero, style: .plain).then { + $0.backgroundColor = .white + $0.separatorStyle = .none + } + + // MARK: - View Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + self.setUI() + self.setLayout() + self.setDelegate() + } +} + +// MARK: - Methods + +extension DepartureSearchVC { + private func setDelegate() { + self.naviBar.delegate = self + self.locationTableView.delegate = self + self.locationTableView.dataSource = self + } +} + +// MARK: - UI & Layout + +extension DepartureSearchVC { + private func setUI() { + view.backgroundColor = .w1 + } + + private func setLayout() { + view.addSubviews(naviBar, dividerView, locationTableView) + + naviBar.snp.makeConstraints { make in + make.leading.top.trailing.equalTo(view.safeAreaLayoutGuide) + make.height.equalTo(48) + } + + dividerView.snp.makeConstraints { make in + make.top.equalTo(naviBar.snp.bottom) + make.leading.trailing.equalTo(view.safeAreaLayoutGuide) + make.height.equalTo(6) + } + + locationTableView.snp.makeConstraints { make in + make.top.equalTo(dividerView.snp.bottom) + make.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) + } + } +} + +// MARK: - UITableViewDelegate, UITableViewDataSource + +extension DepartureSearchVC: UITableViewDelegate, UITableViewDataSource { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return 5 + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + return UITableViewCell() + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return 68 + } +} + +// MARK: - CustomNavigationBarDelegate + +extension DepartureSearchVC: CustomNavigationBarDelegate { + func searchButtonDidTap(text: String) { + print(text) + // 서버 통신 구현 + } +} From dbe7ee9fc2e2939fff21f8af8b878c354abc5316 Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 2 Jan 2023 17:19:55 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[Feat]=20#13=20-=20LocationSearchResultTVC?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Runnect-iOS.xcodeproj/project.pbxproj | 6 +- .../Global/Literal/ImageLiterals.swift | 2 + .../ic_alert.imageset/Contents.json | 23 +++++ .../ic_alert.imageset/Group 9279.png | Bin 0 -> 1112 bytes .../ic_alert.imageset/Group 9279@2x.png | Bin 0 -> 2225 bytes .../ic_alert.imageset/Group 9279@3x.png | Bin 0 -> 3422 bytes .../ic_location_point.imageset/Contents.json | 23 +++++ .../ic_location_point.imageset/Vector.png | Bin 0 -> 347 bytes .../ic_location_point.imageset/Vector@2x.png | Bin 0 -> 637 bytes .../ic_location_point.imageset/Vector@3x.png | Bin 0 -> 926 bytes .../CourseDrawing/VC/DepartureSearchVC.swift | 17 +++- .../Presentation/CourseDrawing/Views/.gitkeep | 0 .../Views/LocationSearchResultTVC.swift | 82 ++++++++++++++++++ 13 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Contents.json create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Group 9279.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Group 9279@2x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Group 9279@3x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Contents.json create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector@2x.png create mode 100644 Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector@3x.png delete mode 100644 Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/.gitkeep create mode 100644 Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/LocationSearchResultTVC.swift diff --git a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj index 71603320..b43fa2f6 100644 --- a/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj +++ b/Runnect-iOS/Runnect-iOS.xcodeproj/project.pbxproj @@ -62,6 +62,7 @@ CE665610295D92C200C64E12 /* setTextLineHeight.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE66560F295D92C200C64E12 /* setTextLineHeight.swift */; }; CE665612295D92E400C64E12 /* UserDefaultWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE665611295D92E400C64E12 /* UserDefaultWrapper.swift */; }; CE665615295D989A00C64E12 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = CE665614295D989A00C64E12 /* .swiftlint.yml */; }; + CEB8416E2962C45300BF8080 /* LocationSearchResultTVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB8416D2962C45300BF8080 /* LocationSearchResultTVC.swift */; }; CEC2A6852961F92C00160BF7 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6842961F92C00160BF7 /* CustomButton.swift */; }; CEC2A68729629B9B00160BF7 /* SignInVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A68629629B9B00160BF7 /* SignInVC.swift */; }; CEC2A68A2962ADCD00160BF7 /* RNMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC2A6892962ADCD00160BF7 /* RNMapView.swift */; }; @@ -141,6 +142,7 @@ CE66560F295D92C200C64E12 /* setTextLineHeight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = setTextLineHeight.swift; sourceTree = ""; }; CE665611295D92E400C64E12 /* UserDefaultWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultWrapper.swift; sourceTree = ""; }; CE665614295D989A00C64E12 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = ""; }; + CEB8416D2962C45300BF8080 /* LocationSearchResultTVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSearchResultTVC.swift; sourceTree = ""; }; CEC2A6842961F92C00160BF7 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = ""; }; CEC2A68629629B9B00160BF7 /* SignInVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInVC.swift; sourceTree = ""; }; CEC2A6892962ADCD00160BF7 /* RNMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNMapView.swift; sourceTree = ""; }; @@ -152,7 +154,6 @@ CEEC6B3B2961C51A00D00E1E /* CourseStorageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseStorageVC.swift; sourceTree = ""; }; CEEC6B3D2961C53700D00E1E /* CourseDiscoveryVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CourseDiscoveryVC.swift; sourceTree = ""; }; CEEC6B3F2961C55000D00E1E /* MyPageVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageVC.swift; sourceTree = ""; }; - CEEC6B412961C58B00D00E1E /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CEEC6B422961C59600D00E1E /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CEEC6B432961C59F00D00E1E /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; CEEC6B442961C5A800D00E1E /* .gitkeep */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitkeep; sourceTree = ""; }; @@ -268,7 +269,7 @@ CE17F0402961C3CD00E1DED0 /* Views */ = { isa = PBXGroup; children = ( - CEEC6B412961C58B00D00E1E /* .gitkeep */, + CEB8416D2962C45300BF8080 /* LocationSearchResultTVC.swift */, ); path = Views; sourceTree = ""; @@ -818,6 +819,7 @@ CEC2A68E2962AF2C00160BF7 /* RNMarker.swift in Sources */, CE6655D2295D862A00C64E12 /* Publisher+Driver.swift in Sources */, CE6655E6295D887F00C64E12 /* UIStackView+.swift in Sources */, + CEB8416E2962C45300BF8080 /* LocationSearchResultTVC.swift in Sources */, CE6655CA295D84DD00C64E12 /* UserDefaultKeyList.swift in Sources */, CE6655F2295D894D00C64E12 /* UIView+.swift in Sources */, CE665600295D915D00C64E12 /* getClassName.swift in Sources */, diff --git a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift index 4cd9b493..0cedee41 100644 --- a/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift +++ b/Runnect-iOS/Runnect-iOS/Global/Literal/ImageLiterals.swift @@ -35,6 +35,8 @@ enum ImageLiterals { static var icStorageFill: UIImage { .load(named: "ic_storage_fill") } static var icStorage: UIImage { .load(named: "ic_storage") } static var icTime: UIImage { .load(named: "ic_time") } + static var icLocationPoint: UIImage { .load(named: "ic_location_point") } + static var icAlert: UIImage { .load(named: "ic_alert") } // img static var imgBackground: UIImage { .load(named: "img_background") } static var imgLogo: UIImage { .load(named: "img_logo") } diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Contents.json b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Contents.json new file mode 100644 index 00000000..20315ec1 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Group 9279.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Group 9279@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Group 9279@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Group 9279.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_alert.imageset/Group 9279.png new file mode 100644 index 0000000000000000000000000000000000000000..9099726795acfe83e9ea375144f3634de6cfffe5 GIT binary patch literal 1112 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 ofR*j@4Cb_6hdmmdKI;Vst0GktlmH+?% literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector@2x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2b60211647f5eef0fe0463be6c4498a54316d2fa GIT binary patch literal 637 zcmV-@0)qXCP)$C_Fbq>^9!~;vI-NNK$U%T6$K!E! z4cG|UZnqx*Oz8#zxEhT{GZ6$Ydb~0`1G-Ns!U^ZXL*8I&t7!wm8X9Bbazg>y?RN8) zAO(!KApdg-9YW?~1wZrv*$^fdkC0to^dNEO^4oLu23eTkS>tDdr$_($z?1meSa{X% z;{EJkxP<$QS~H)Q2n$_Uprna`Yfq8|yhs}$g}9Him1GT#Eh`deMv71omQp`F9&j@F zBr7FdnvHK111g{Hdu$ja8gX$YMX(tvCI<#(l7*HmEbM_;fH|QIQg@>mO(n0aH?PVZ zdp@v1y#O`|3*zjH^8MgSj|=e~?d(lY85>?|-Db1-)r@oTnZXL#)^{9}jmP7@vBXbu zl)Z6>j*v@L;dh?iD^jxWMr8e!jf`qZ-DUK^<8h5J|JB#v?j=+sn3%J;vh$) zl$R1@4anqLzX)=LX%LorAEA6qq{`s}aRRY0(X=T+?4C?q=1@admQ4^2W6wfXu4DfI XCgmI#4OM%u00000NkvXXu0mjfRH_HR literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector@3x.png b/Runnect-iOS/Runnect-iOS/Global/Resource/Assets.xcassets/ic_location_point.imageset/Vector@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..8ba0ba010375af1f35718898a5c21a0bc6be85b6 GIT binary patch literal 926 zcmV;P17ZA$P)QyeX6tJRo;rVkrs<9@rdJDVHTiP$0ka z5BJE?NE^1XV`%g6WgqO+YSsBAR|eGk1obZYeJ45iv3I!vWO*c#qm#9V;3i-Xhe;#{ zVv#rkPSs$tUsMO$11IJ^eu~8ru>0ra%8%J>_D__t5?Fx*!_cIx12ht0=;wa$ zFhQ^A7+2t^XU`GjLHjGp&2xULH54T<@U0Fpg8k6{hv?DsaXM6fjW&h_N18D-Ze}B* zL*QevKr;gU$Kn9ya+>}yg-5D25FL!T!H5n)Wj>cjU0XZHI5jz2KU@SP7mE&UaR4@@ z9k(JmZB-PC17P4kHT`k$mOgyYr)CfqdDW_xj#$1+NDX32ZmAn1Eo}ya4Gl!;6(G48 z$xTEF42HE8nr(g`r@+Rk7mLwm{|r&1F+@g(WIm9 z3+o~CI5`t6u|ZY8+OPT%+(+V;`s@M3#vm5e>8tu5;)K*H0pn&EhPA7IRrQ6`iW6%y z=LGyW2TgUrROC_@W8WKVh#5*;`xlc+ty$EyL5+>&p)RUZAdQZy!ki6DkvPJc9Koz>%07*qoM6N<$f}t9o AVgLXD literal 0 HcmV?d00001 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift index 4c919df2..100ffebc 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift @@ -22,6 +22,11 @@ final class DepartureSearchVC: UIViewController { $0.separatorStyle = .none } + private let emptyDataView = UIView().then { + let alertImageView = UIImageView() + alertImageView.image = ImageLiterals.icAlert + } + // MARK: - View Life Cycle override func viewDidLoad() { @@ -29,6 +34,7 @@ final class DepartureSearchVC: UIViewController { self.setUI() self.setLayout() self.setDelegate() + self.registerCell() } } @@ -40,6 +46,11 @@ extension DepartureSearchVC { self.locationTableView.delegate = self self.locationTableView.dataSource = self } + + private func registerCell() { + self.locationTableView.register(LocationSearchResultTVC.self, + forCellReuseIdentifier: LocationSearchResultTVC.className) + } } // MARK: - UI & Layout @@ -78,7 +89,11 @@ extension DepartureSearchVC: UITableViewDelegate, UITableViewDataSource { } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - return UITableViewCell() + guard let cell = tableView.dequeueReusableCell(withIdentifier: LocationSearchResultTVC.className, for: indexPath) + as? LocationSearchResultTVC + else { return UITableViewCell() } + cell.selectionStyle = .none + return cell } func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/.gitkeep b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/LocationSearchResultTVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/LocationSearchResultTVC.swift new file mode 100644 index 00000000..7e2edb92 --- /dev/null +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/Views/LocationSearchResultTVC.swift @@ -0,0 +1,82 @@ +// +// LocationSearchResultTVC.swift +// Runnect-iOS +// +// Created by sejin on 2023/01/02. +// + +import UIKit + +final class LocationSearchResultTVC: UITableViewCell { + + // MARK: - UI Components + + private let locationPointImageView = UIImageView().then { + $0.image = ImageLiterals.icLocationPoint + $0.tintColor = .g3 + } + + private let locationLabel = UILabel().then { + $0.text = "장소" + $0.font = .b1 + $0.textColor = .g1 + } + + private let detailLocationLabel = UILabel().then { + $0.text = "상세 주소" + $0.font = .b6 + $0.textColor = .g2 + } + + private lazy var locationStackView = UIStackView(arrangedSubviews: [locationLabel, detailLocationLabel]).then { + $0.axis = .vertical + $0.spacing = 4 + $0.alignment = .leading + } + + private let dividerView = UIView().then { + $0.backgroundColor = .g4 + } + + // MARK: - initialization + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + self.setUI() + self.setLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - UI & Layout + +extension LocationSearchResultTVC { + private func setUI() { + self.backgroundColor = .w1 + self.contentView.backgroundColor = .w1 + } + + private func setLayout() { + self.addSubviews(locationPointImageView, locationStackView, dividerView) + + locationPointImageView.snp.makeConstraints { make in + make.leading.equalToSuperview().inset(24) + make.centerY.equalToSuperview() + } + + locationStackView.snp.makeConstraints { make in + make.leading.equalTo(locationPointImageView.snp.trailing).offset(14) + make.centerY.equalToSuperview() + make.trailing.equalToSuperview().inset(24) + } + + dividerView.snp.makeConstraints { make in + make.bottom.equalToSuperview() + make.leading.trailing.equalToSuperview() + make.height.equalTo(1) + } + } +} From b7e1af32f91d1b81e6e8817782dc100d1a99cdde Mon Sep 17 00:00:00 2001 From: Sejin Lee Date: Mon, 2 Jan 2023 19:48:07 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[Feat]=20#13=20-=20Empty=20View=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CourseDrawing/VC/DepartureSearchVC.swift | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift index 100ffebc..a037957e 100644 --- a/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift +++ b/Runnect-iOS/Runnect-iOS/Presentation/CourseDrawing/VC/DepartureSearchVC.swift @@ -22,9 +22,23 @@ final class DepartureSearchVC: UIViewController { $0.separatorStyle = .none } - private let emptyDataView = UIView().then { - let alertImageView = UIImageView() - alertImageView.image = ImageLiterals.icAlert + private let alertImageView = UIImageView().then { + $0.image = ImageLiterals.icAlert + $0.tintColor = .g3 + } + + private let descriptionLabel = UILabel().then { + $0.text = "검색결과가 없습니다\n검색어를 다시 확인해주세요" + $0.font = .b4 + $0.textColor = .g3 + $0.numberOfLines = 2 + $0.textAlignment = .center + } + + private lazy var emptyDataView = UIStackView(arrangedSubviews: [alertImageView, descriptionLabel]).then { + $0.axis = .vertical + $0.spacing = 22 + $0.alignment = .center } // MARK: - View Life Cycle @@ -58,6 +72,7 @@ extension DepartureSearchVC { extension DepartureSearchVC { private func setUI() { view.backgroundColor = .w1 + emptyDataView.isHidden = true // 데이터가 없으면 false로 설정 } private func setLayout() { @@ -78,6 +93,11 @@ extension DepartureSearchVC { make.top.equalTo(dividerView.snp.bottom) make.leading.bottom.trailing.equalTo(view.safeAreaLayoutGuide) } + + locationTableView.addSubview(emptyDataView) + emptyDataView.snp.makeConstraints { make in + make.center.equalToSuperview() + } } }