web-dev-qa-db-fra.com

Sélecteur multi-composants (UIPickerView) dans SwiftUI

J'essaie d'ajouter un sélecteur à trois composants (UIPickerView) à une application SwiftUI (dans une application UIKit traditionnelle, la source de données renverrait 3 à partir de la méthode numberOfComponents), mais je ne trouve aucun exemple de cela nulle part.

J'ai essayé d'ajouter un HStack de trois sélecteurs à un seul composant, mais la perspective est différente de ce que ce serait s'ils faisaient tous partie d'un seul sélecteur.

7
Frank Schmitt

Voici une adaptation des solutions ci-dessus, à l'aide du sélecteur UIKit:

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)
        }
    }

    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()
    }
}
1
protasm

Ce n'est pas aussi élégant, mais cela n'implique pas le portage sur des trucs UIKit. Je sais que vous avez mentionné que la perspective était éteinte dans votre réponse, mais peut-être que la géométrie ici corrige

GeometryReader { geometry in

    HStack
    {
         Picker(selection: self.$selection, label: Text(""))
         {
              ForEach(0 ..< self.data1.count)
              {
                  Text(self.data1[$0])
                     .color(Color.white)
                     .tag($0)
              }
          }
          .pickerStyle(.wheel)
          .fixedSize(horizontal: true, vertical: true)
          .frame(width: geometry.size.width / 2, height: geometry.size.height, alignment: .center)


          Picker(selection: self.$selection2, label: Text(""))
          {
               ForEach(0 ..< self.data2.count)
               {
                   Text(self.data2[$0])
                       .color(Color.white)
                       .tag($0)
               }
          }
          .pickerStyle(.wheel)
          .fixedSize(horizontal: true, vertical: true)
          .frame(width: geometry.size.width / 2, height: geometry.size.height, alignment: .center)

    }
}

En utilisant la géométrie et en fixant la taille comme celle-ci, les deux cueilleurs occupent soigneusement la moitié de la largeur de l'écran dans chaque moitié. Maintenant, il vous suffit de gérer la sélection à partir de deux variables d'état différentes au lieu d'une, mais je préfère cette méthode car elle conserve tout dans Swift UI

0
AngryDuck