DeveloperAcademy-POSTECH / 2024-MC3-A16-PalangPalang

๐Ÿฆ‹ ์ค๋Œ€์žˆ๋Š” ํŒ”๋ž‘๊ฑฐ๋ฆผ ๐Ÿฆ‹
0 stars 4 forks source link

Vertical Custom Picker ๊ตฌํ˜„๋ฐฉ์‹ #6

Closed shippingpark closed 2 weeks ago

Dorii0513 commented 1 month ago

1. Picker๋ž€?

@MainActor @preconcurrency
struct Picker<Label, SelectionValue, Content> where Label : View, SelectionValue : Hashable, Content : View
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 13 31

์ด๋Ÿฐ ์‹์œผ๋กœ key ๊ฐ’์„ ํ•ด์‹ฑ ํ•จ์ˆ˜์— ๋„ฃ์–ด ํ•ด์‹œํ•˜์—ฌ โ†’ ๋ฐฐ์—ด์˜ ์ฃผ์†Œ ๊ฐ’์„ ์–ป๊ณ , ๊ทธ ์ฃผ์†Œ๊ฐ’์— ๋งž๋Š” index์— value ๊ฐ’์„ ์ €์žฅํ•œ๋‹ค๊ณ  ํ•จ. ์ด๋•Œ, ํ•ด์‹œํ…Œ์ด๋ธ”์€ ์ˆœ์„œ๋ฅผ ์ง€ํ‚ค์ง€ ์•Š๊ณ  ์ €์žฅ ๋จ!!

๋”ฐ๋ผ์„œ ๋ฐฐ์—ด์— ์ €์žฅ๋œ ๊ฐ’์„ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด, index ๊ฐ’์„ ์•Œ์•„์•ผ ํ•˜๋Š”๋ฐ ์ด index ๊ฐ’์ด ์ˆœ์„œ๋Œ€๋กœ ๋˜์–ด ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— key ๊ฐ’์„ ์•Œ์•„์•ผ ํ•˜๋Š” ๊ฒƒ์ž„ (์šฐ๋ฆฐ value๊ฐ€ ์ €์žฅ๋œ ํ•ด์‹œํ…Œ์ด๋ธ”์˜ index๋ฅผ ๋ชจ๋ฆ„

โ†’ ์ฆ‰ Key๋ฅผ ํ†ตํ•ด ํ•ด์‹œํ…Œ์ด๋ธ”์˜ index๋ฅผ ์•Œ์•„์•ผ ํ•ด๋‹น value์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋จ

๋”ฐ๋ผ์„œ ํ•ด์‹œํ…Œ์ด๋ธ”์ด๋ž€ key ๋ผ๋Š” ๊ฒƒ์„ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ฃผ์†Œ๊ฐ’(index)๋กœ ๋ฐ”๊พธ๊ณ  ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ•ด์‹œํ…Œ์ด๋ธ”์— ์ ‘๊ทผํ•ด value๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜, ์ €์žฅํ•˜๋Š” ํ˜•ํƒœ๋ฅผ ๋งํ•จ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 12 08
    enum Flavor: String, CaseIterable, Identifiable {
        case chocolate, vanilla, strawberry
        var id: Self { self }
    }

    @State private var selectedFlavor: Flavor = .chocolate
    //Pikcer์˜ ๊ธฐ๋ณธ ์„ธํŒ… ๊ฐ’์„ @State๋กœ ์„ค์ •ํ•œ๋‹ค

    //์œ„์˜ ์—ด๊ฑฐํ˜• ๊ฐ’ ์ค‘์—์„œ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” Picker ๋งŒ๋“ค๊ธฐ
    //selection์€ ์œ„์— State๋ณ€์ˆ˜๋กœ ์„ ์–ธํ•œ ๊ฐ’์„ ๋ฐ”์ธ๋”ฉํ•˜์—ฌ ๋„ฃ๋Š”๋‹ค
    List {
        Picker("Flavor", selection: $selectedFlavor) {
            Text("Chocolate").tag(Flavor.chocolate)
            Text("Vanilla").tag(Flavor.vanilla)
            Text("Strawberry").tag(Flavor.strawberry)
        }
    }

โ‰๏ธ๊ทผ๋ฐ ์ด ํƒœ๊ทธ๊ฐ€ ๋จธํ•˜๋Š” ์•ค์ง€ ๋ชจ๋ฅด๊ฒ ์Œ ใ… ใ…  โ†’ ๋„ค๋น„๊ฒŒ์ด์…˜ํ•  ๋•Œ ์“ฐ๋Š” ๊ฑฐ ๊ฐ™์Œ

    Picker("Flavor", selection: $selectedFlavor) {
        ForEach(Flavor.allCases) { flavor in
            Text(flavor.rawValue.capitalized)
        }
    }

โ‰๏ธForeach๊ฐ€ ์ž๋™์œผ๋กœ ID ๊ฐ’์„ ํ™œ์šฉํ•ด tag๋ฅผ ํ• ๋‹นํ•œ๋‹ค๋Š”๋ฐ โ†’ Flavor๊ฐ€ ์‹๋ณ„ ๊ฐ€๋Šฅํ•œ ํ”„๋กœํ† ์ฝœ์„ ์ค€์ˆ˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋ผ๊ณ ํ•จโ€ฆ์ด๊ฒŒ ๋ฌด์Šจ ๋ง..??

*์œ„์˜ ์˜ˆ๋Š” Flavor๊ฐ€ ์„ ํƒ ์œ ํ˜•๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋„๋ก id ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์œ ํ˜•์„ ์ •์˜ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์— ์˜์กดํ•œ๋‹ค๊ณ  ํ•จ. ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ํƒœ๊ทธ๋ฅผ ์žฌ์ •์˜ํ•ด์•ผ ํ•จ!*

โ‡’ **Foreach**
    struct ForEach<Data, ID, Content> where Data : RandomAccessCollection, ID : Hashable

๋ชจ๋ฅด๊ฒ ๋Š” ๋ถ€๋ถ„


2. StylingPickers

[PickerStyle | Apple Developer Documentation](https://developer.apple.com/documentation/swiftui/pickerstyle)

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 16 06

์• ํ”Œ์—์„œ๋Š” Picker์˜ ์Šคํƒ€์ผ์„ ์ปค์Šคํ…€ํ•  ์ˆ˜ ์žˆ๋„๋ก PickerStyle ์ด๋ผ๋Š” ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Œ!!

VStack {
    Picker("Flavor", selection: $selectedFlavor) {
        ForEach(Flavor.allCases) { flavor in
            Text(flavor.rawValue.capitalized)
        }
    }
    Picker("Topping", selection: $selectedTopping) {
        ForEach(Topping.allCases) { topping in
            Text(topping.rawValue.capitalized)
        }
    }
}
.pickerStyle(.segmented)

๋งŒ์•ฝ pickerStyle ์„ .wheel ๋กœ ํ•˜๋ฉด vertical scrollํ•˜๋Š” picker๊ฐ€ ์ƒ์„ฑ!


3. Timer์— ์žˆ๋Š” Picker๋Š” ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค๊นŒ?

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 16 36

์ผ๋‹จ Picker๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š” ์ง€๋Š” ์œ„์—์„œ ๋ฐฐ์› ๋Š”๋ฐ, ์–˜๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜์ง€??

๊ณ ๋ฏผํ•ด ๋ดค์„ ๋•Œ!

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 16 53

์ด๋ ‡๊ฒŒ ์„น์…˜์„ ๋‚˜๋ˆ„์–ด์„œ Picker 3๊ฐœ๋ฅผ ๋งŒ๋“ค์–ด์•ผํ• ๊นŒ?

import SwiftUI

struct ContentView: View {
    var body: some View {
        @State var hour = 0
        @State var minute = 0
        @State var second = 0

        var hours = [Int](0..<24)
        var minutes = [Int](0..<60)
        var seconds = [Int](0..<60)

        HStack {
            Picker(selection: $hour, label: Text("")){
                ForEach(0..<24){ hour in
                    Text("\(hours[hour]) ์‹œ๊ฐ„").tag(hour)
                }
            }
            Picker(selection: $minute, label: Text("")){
                ForEach(0..<60){ minute in
                    Text("\(minutes[minute]) ๋ถ„").tag(hour)
                }
            }
            Picker(selection: $second, label: Text("")){
                ForEach(0..<60){ second in
                    Text("\(seconds[second]) ์ดˆ").tag(hour)
                }
            }
        }.pickerStyle(.wheel)
            .padding()
    }
}
แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 17 09

์ด๋ ‡๊ฒŒ ๋‚˜์˜ด;;ใ…œใ…œ

๊ตฌ๊ธ€๋ง ํ•ด๋ณด๋‹ˆ๊นŒ

[Multi-Component Picker (UIPickerView) in SwiftUI](https://stackoverflow.com/questions/56567539/multi-component-picker-uipickerview-in-swiftui)

Multi Component Picker ๊ตฌํ˜„ํ•˜๊ธฐ

//
//  ContentView.swift
//  customPicker
//
//  Created by ๊น€์˜ˆ๋ฆผ on 7/28/24.
//

import SwiftUI

struct PickerView: UIViewRepresentable {
    var data: [[String]]
    @Binding var selections: [Int]

    //makeCoordinator()
    func makeCoordinator() -> PickerView.Coordinator {
        Coordinator(self)
    }

    //makeUIView(context:)
    func makeUIView(context: UIViewRepresentableContext<PickerView>) -> UIPickerView {
        let picker = UIPickerView(frame: .zero)

        picker.dataSource = context.coordinator
        picker.delegate = context.coordinator

        return picker
    }

    //updateUIView(_:context:)
    func updateUIView(_ view: UIPickerView, context: UIViewRepresentableContext<PickerView>) {
        for i in 0...(self.selections.count - 1) {
            view.selectRow(self.selections[i], inComponent: i, animated: false)
        }
        context.coordinator.parent = self // fix
    }

    class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
        var parent: PickerView

        //init(_:)
        init(_ pickerView: PickerView) {
            self.parent = pickerView
        }

        //numberOfComponents(in:)
        func numberOfComponents(in pickerView: UIPickerView) -> Int {
            return self.parent.data.count
        }

        //pickerView(_:numberOfRowsInComponent:)
        func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
            return self.parent.data[component].count
        }

        //pickerView(_:titleForRow:forComponent:)
        func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
            return self.parent.data[component][row]
        }

        //pickerView(_:didSelectRow:inComponent:)
        func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
            self.parent.selections[component] = row
        }
    }
}

import SwiftUI

struct ContentView: View {
    private let data: [[String]] = [
        Array(0...10).map { "\($0)" },
        Array(20...40).map { "\($0)" },
        Array(100...200).map { "\($0)" }
    ]

    @State private var selections: [Int] = [5, 10, 50]

    var body: some View {
        VStack {
            PickerView(data: self.data, selections: self.$selections)

            Text("\(self.data[0][self.selections[0]]) \(self.data[1][self.selections[1]]) \(self.data[2][self.selections[2]])")
        } //VStack
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

#Preview {
    ContentView()
}

[[SwiftUI] Picker ๋ง›๋ณด๊ธฐ](https://sujinnaljin.medium.com/swiftui-picker-%EB%A7%9B%EB%B3%B4%EA%B8%B0-d745494f9a1c)

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 17 32

Picker์˜ ์˜์—ญ์„ ์กฐ์ ˆํ•˜๋Š” ๋ฐฉ๋ฒ•

//
//  ContentView.swift
//  customPicker
//
//  Created by ๊น€์˜ˆ๋ฆผ on 7/28/24.
//

import SwiftUI

struct ContentView: View {

    @State var hour: Int
    @State var minute: Int

    var hours = [Int](0..<24)
    var minutes = [Int](0..<60)

    var body: some View {

        HStack(spacing: 0) {
            Picker("hours", selection: $hour) {
                ForEach (0..<24) { hour in
                    Text("\(hours[hour])")
                }
            }
            .pickerStyle(.wheel)
            Text(":")
                .font(.title)
                .fontWeight(.heavy)
            Picker("hours", selection: $minute) {
                ForEach (0..<60) { minute in
                    Text("\(minutes[minute])")
                }
            }
            .pickerStyle(.wheel)
        }
        .frame(width: 100, height: 100)
    }
}

#Preview {
    ContentView(hour: 0, minute: 0)
}

Picker์˜ ์˜์—ญ์€ .frame ์„ ํ™œ์šฉํ•˜์—ฌ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Œ

HStack์— .frame(width: 100, height: 100) ์„ ๊ฑธ์–ด์„œ ์กฐ์ ˆ ๊ฐ€๋Šฅ

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 17 54

์—ฌ๊ธฐ์„œ ๋†’์ด๋ฅผ .frame(width: 100, height: 50)๋กœ ๋” ์ค„์ด๋ฉด

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์˜์—ญ์ด ๋” ์ค„์–ด๋“ค๊ฒŒ ๋จ!

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2024-07-29 แ„‹แ…ฉแ„’แ…ฎ 1 18 26