[SwiftUI] UberClone: RideRequest 2

Junyoung ParkΒ·2022λ…„ 11μ›” 19일
0

SwiftUI

λͺ©λ‘ 보기
118/136
post-thumbnail
post-custom-banner

πŸ”΄ Let's Build UBER with SwiftUI | iOS 16 & Xcode 14

UberClone: RideRequest 2

κ΅¬ν˜„ λͺ©ν‘œ

  • 배달 μš”μ²­ λ·° μΈν„°λ ‰μ…˜

κ΅¬ν˜„ νƒœμŠ€ν¬

  • 배달 μ°¨λŸ‰ μ΄λ„˜ν™”
  • μžλ™ μœ„μΉ˜ 계산을 μœ„ν•œ ν•΄λ‹Ή 클래슀의 μ‹±κΈ€ν„΄ κ΅¬ν˜„
  • μ—°μ‚° ν”„λ‘œνΌν‹°λ₯Ό ν†΅ν•œ μžλ™ μœ„μΉ˜ 계산 및 λΉ„μš© 좜λ ₯

핡심 μ½”λ“œ

import Foundation

enum RideType: Int, CaseIterable, Identifiable {
    case uberX
    case black
    case uberXL
    
    var id: Int { return rawValue }
    
    var description: String {
        switch self {
        case .uberX:
            return "UberX"
        case .black:
            return "UberBlack"
        case .uberXL:
            return "UberXL"
        }
    }
    
    var imageName: String {
        switch self {
        case .uberX:
            return "uber_x"
        case .black:
            return "uber_black"
        case .uberXL:
            return "uber_xl"
        }
    }
    
    var fair: Double {
        switch self {
        case .uberX: return 10
        case .black: return 20
        case .uberXL: return 15
        }
    }
    
    func computedPrice(for distanceInMeters: Double) -> Double {
        let distanceInMiles = distanceInMeters / 1600
        switch self {
        case .uberX:
            return distanceInMiles * 1.5 + fair
        case .black:
            return distanceInMiles * 2.0 + fair
        case .uberXL:
            return distanceInMiles * 1.75 + fair
        }
    }
}
  • λ¦¬μŠ€νŠΈμ— 각 νƒ€μž… 별 μ‹λ³„μžλ₯Ό μ£ΌκΈ° μœ„ν•œ Identificable ν”„λ‘œν† μ½œμ„ λ”°λ₯΄κΈ° μœ„ν•΄ id 값을 μ‹λ³„μžλ‘œ 리턴 (μ—°μ‚° ν”„λ‘œνΌν‹°)
  • 각 μ΄λ„˜ νƒ€μž…μ— 맞좰 이미지 이름, λΉ„μš©, 거리가 듀어왔을 λ•Œ μžλ™μœΌλ‘œ λΉ„μš©μ„ κ³„μ‚°ν•˜λŠ” ν•¨μˆ˜ λ“± κ΅¬ν˜„
    @State private var selectedRideType: RideType = .uberX

...

                    ForEach(RideType.allCases) { ride in
                        VStack(alignment: .leading) {
                            Image(ride.imageName)
                                .resizable()
                                .scaledToFit()
                            
                            VStack(alignment: .leading,  spacing: 4) {
                                Text(ride.description)
                                    .font(.system(size: 14, weight: .semibold))
                                Text(viewModel.computeRidePrice(for: ride).asCurrency)
                                    .font(.system(size: 14, weight: .semibold))
                            }
                            .padding(8)
                        }
                        .frame(width: 112, height: 140)
                        .foregroundColor(ride == selectedRideType ? .white : .black)
                        .background(Color(ride == selectedRideType ? .systemBlue : .systemGroupedBackground))
                        .scaleEffect(ride == selectedRideType ? 1.1 : 1)
                        .cornerRadius(10)
                        .onTapGesture {
                            withAnimation(.spring()) {
                                selectedRideType = ride
                            }
                        }
                    }
  • μ‘΄μž¬ν•˜λŠ” λͺ¨λ“  μ’…λ₯˜μ˜ μ΄λ„˜ νƒ€μž…μ„ λ°˜λ³΅ν•˜λ©΄μ„œ 리슀트둜 ν‘œν˜„
  • ν•΄λ‹Ή 뷰의 @State ν”„λ‘œνΌν‹°λ₯Ό 톡해 νŠΉμ • μΉ΄λ“œ 선택을 체크, 선택 여뢀에 λ”°λΌμ„œ λ‹€λ₯Έ μΉ΄λ“œμ™€ λ‹€λ₯Έ 효과(색깔, μŠ€μΌ€μΌ μ—¬λΆ€ λ“±) μ£ΌκΈ°
.onReceive(LocationManager.shared.$userLocation) { location in
            if let location = location {
                viewModel.userLocation = location
            }
        }
  • μœ„μ˜ λΉ„μš© 계산을 μœ„ν•΄ 도착 μœ„μΉ˜ 및 좜발 μœ„μΉ˜κ°€ ν•„μš”
  • 좜발 μœ„μΉ˜λŠ” 곧 지역 섀정을 λ‹΄λ‹Ήν•˜λŠ” ν΄λž˜μŠ€μ—μ„œ λ°›μ•„μ˜€λŠ” μœ μ € 정보
  • μ‹±κΈ€ν„΄ νŒ¨ν„΄μ„ 톡해 ν•΄λ‹Ή 값을 ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€ λ‚΄μ—μ„œ μ§€μ†μ μœΌλ‘œ μœ μ§€, ν™ˆ λ·°μ—μ„œ ν•΄λ‹Ή 값을 ν™˜κ²½ λ³€μˆ˜λ‘œ μ‚¬μš©ν•˜λŠ” λ·° λͺ¨λΈ λ‚΄ ν”„λ‘œνΌν‹°λ‘œ μ§€μ†μ μœΌλ‘œ 전달
func computeRidePrice(for ride: RideType) -> Double {
        guard
            let destinationCoordinate = selectedLocation,
            let startCoordinate = userLocation else { return 0.0 }
        let start = CLLocation(latitude: startCoordinate.latitude, longitude: startCoordinate.longitude)
        let dest = CLLocation(latitude: destinationCoordinate.latitude, longitude: destinationCoordinate.longitude)
        let distanceInMeters = start.distance(from: dest)
        return ride.computedPrice(for: distanceInMeters)
    }
  • λ‘œμΌ€μ΄μ…˜ λ§€λ‹ˆμ €μ—μ„œ ν™ˆ λ·°λ₯Ό 톡해 μ§€μ†μ μœΌλ‘œ μ—…λ°μ΄νŠΈκ°€ 보μž₯, ν•΄λ‹Ή λ·° λͺ¨λΈμ—μ„œ 좜발-도착 정보 κ°„μ˜ 차이λ₯Ό μžλ™μœΌλ‘œ μ—°μ‚° κ°€λŠ₯

κ΅¬ν˜„ ν™”λ©΄

μ „μ²΄μ μœΌλ‘œ μœ„ κ°•μ˜λŠ” ν™˜κ²½ λ³€μˆ˜λ₯Ό 맀우 μœ μš©ν•˜κ²Œ μ ‘κ·Όν•˜λŠ” 것 같은데, κ·ΈλŸΌμ—λ„ λΆˆκ΅¬ν•˜κ³  λ©”λͺ¨λ¦¬ λˆ„μˆ˜μ™€ 같은 일은 κ±±μ •ν•˜μ§€ μ•Šμ„ 수 μ—†λ‹€. DIλ₯Ό 톡해 ν•΄κ²°ν•  수 μžˆκ² μ§€λ§Œ, μœ„μ™€ 같은 μ½”λ”©μ˜ μš©μ΄μ„±μ€ 맀λ ₯적이닀. λ¬Όλ‘  μš°λ²„μ™€ 같이 μœ„μΉ˜ 정보λ₯Ό μ§€μ†μ μœΌλ‘œ μ ‘κ·Όν•˜λŠ” 것이 ν•„μˆ˜ λΆˆκ°€κ²°ν•œ κ²½μš°μ—λŠ” ν™˜κ²½ λ³€μˆ˜κ°€ 해닡일 지도.

profile
JUST DO IT
post-custom-banner

0개의 λŒ“κΈ€