Where who wants to meet someone

Picker 사용기 본문

Apple Developer/iOS(SwiftUI)

Picker 사용기

Lust3r 2024. 1. 23. 20:38
728x90
 

Picker | Apple Developer Documentation

A control for selecting from a set of mutually exclusive values.

developer.apple.com

- 앱에서 Picker를 통해 선택지를 제공해야 할 필요가 있어 찾아보게 되었고, 새로운 지식이기 때문에 정리를 해보려 한다.

 

enum Flavor: String, CaseIterable, Identifiable {
    case chocolate, vanilla, strawberry
    var id: Self { self }
}


@State private var selectedFlavor: Flavor = .chocolate
  • 예제에서는 Picker에서 제공할 항목들을 enum의 각 case로 나열했다.
    • String: 각각의 case는 대응하는 raw value가 String 타입임을 나타냄
    • CaseIterable: 열거형의 모든 케이스를 컬렉션으로 제공하는 프로토콜. 이를 채택하면 allCases를 통해 열거형의 모든 케이스에 접근할 수 있음(추후 ForEach에서 사용)
    • Identifiable: 고유한 식별자를 가지는 타입을 나타내는 프로토콜. id라는 프로퍼티를 구현해야 하고, 이는 타입의 인스턴스를 구분할 수 있는 값이어야 함. 여기서는 자기 자신을 id로 사용하고 있음
  • 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)
    • Picker의 label은 Flavor, selection은 일전의 상태를 가지는 selectedFlavor를 바인딩
    • 여기서는 각 항목을 Text를 통해 나열하고, tag를 사용하여 명칭과 실제 항목을 연결시키고 있음
    • Picker만 사용해도 되지만 List를 통해 아래와 같이 보이게 할 수 있음

 

Picker("Flavor", selection: $selectedFlavor) {
    ForEach(Flavor.allCases) { flavor in
        Text(flavor.rawValue.capitalized)
    }
}
  • 하지만 위의 코드처럼 직접 텍스트로 나열하지 않고도 항목을 나열할 수 있음
  • 열거형에 CaseIterable을 채택했기 때문에, ForEach(Flavor.allCases)를 사용할 수 있기 때문
  • 예제 코드 ForEach 내에서 각 항목은 flavor라는 이름으로 각 항목마다 그 rawValue를 Text에 넣어주고 있음
  • Identifiable을 채택, id를 통해 정확히 맞는 타입을 정의했기 때문에 이전처럼 tag를 하지 않아도 자동으로 각 옵션의 id를 사용해서 할당.
    하지만 그렇지 않은 경우에는 tag를 재정의해야 함.
enum Topping: String, CaseIterable, Identifiable {
    case nuts, cookies, blueberries
    var id: Self { self }
}


extension Flavor {
    var suggestedTopping: Topping {
        switch self {
        case .chocolate: return .nuts
        case .vanilla: return .cookies
        case .strawberry: return .blueberries
        }
    }
}


@State private var suggestedTopping: Topping = .nuts
  • 가령 위의 경우에는 맛을 선택했을 때, 맛의 정보가 필요한 것이 아니라 그에 상응하는 토핑의 값이 필요함
List {
    Picker("Flavor", selection: $suggestedTopping) {
        ForEach(Flavor.allCases) { flavor in
            Text(flavor.rawValue.capitalized)
                .tag(flavor.suggestedTopping)
        }
    }
    HStack {
        Text("Suggested Topping")
        Spacer()
        Text(suggestedTopping.rawValue.capitalized)
            .foregroundStyle(.secondary)
    }
}
  • tag를 통해 해당 맛에 해당하는 정보를 flavor의 suggestedTopping으로 재정의를 했고, selection에 넣어주고 있음
  • 그리하여 HStack의 두 번째 Text에는 선택한 Flavor가 아닌 tag의 suggestedTopping이 보이게 됨

 

  • 이외에도 Picker의 ForEach에서 명시적으로 tag 수정자가 필요한 경우는 다음과 같다.
    • id 매개변수 유형으로 Self 이외의 다른 것을 사용하여 Identifiable 프로토콜을 준수하는 열거형의 경우.
      예를 들어 문자열 열거형은 케이스의 rawValue 문자열을 id로 사용할 수 있는데, 이 id 유형은 열거형 자체의 유형인 선택 유형과 일치하지 않음
    • selection 입력 매개변수에 optional 값을 사용하는 경우.
      이 기능을 사용하려면 태그 수정자의 입력을 명시적으로 Optional 로 캐스팅하여 일치시켜야 함.
      이에 대한 예는 tag(_:)를 참조
  • Picker Style은 아래와 같음
    • automatic: 기본 스타일. picker의 문맥에 따라 결정됨
    • radioGroup: 라디오 버튼의 그룹으로 옵션을 보여주는 스타일. iOS 사용 불가. macOS 10.15+

inline: 각 옵션이 현재 컨테이너의 다른 view와 인라인으로 표시되는 선택 스타일
menu: 사용자가 버튼을 누르면 하위 메뉴로 옵션을 표시하는 피커 스타일
navigationLink: 목록 스타일의 picker view를 푸시하여 옵션을 표시하는 navigation link로 표시되는    스타일
palette: 옵션을 컴팩트한 요소의 행으로 표시하는 피커 스타일
segmented: 옵션을 분할된 컨트롤에 표시하는 스타일
wheel: 선택된 옵션과 몇 가지 인접한 옵션을 스크롤 가능한 휠에 표시하는 스타일