はじめに
iOS15からPickerのwheelがバグが発生しました。
これはOSのバグで現時点では解決方法はないようです。
UIKitを使ってちゃんと使えるWheelPickerを作成します。
実装方法
WheelPickerView
struct WheelPickerView: UIViewRepresentable {
@Binding private var selection: Int
private let content: [String]
init(selection: Binding<Int>, content: [String]) {
self._selection = selection
self.content = content
}
func makeUIView(context: Context) -> UIPickerView {
let picker = UIPickerView(frame: .zero)
picker.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
picker.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
picker.dataSource = context.coordinator
picker.delegate = context.coordinator
return picker
}
func updateUIView(_ picker: UIPickerView, context: Context) {
picker.selectRow(selection, inComponent: 0, animated: true)
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
private var wheelPickerView: WheelPickerView
init(_ wheelPickerView: WheelPickerView) {
self.wheelPickerView = wheelPickerView
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return wheelPickerView.content.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return wheelPickerView.content[row]
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
wheelPickerView.selection = row
}
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {
let label = (view as? UILabel) ?? UILabel()
label.text = wheelPickerView.content[row]
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
return label
}
}
}
ContentView
import SwiftUI
struct ContentView: View {
@State var selectIndex: Int = 0
let animals: [String] = ["ライオン", "ニワトリ", "イヌ", "トナカイ", "キツツキ", "モグラ"]
var body: some View {
VStack(alignment: .center, spacing: 50) {
Text("好きな動物は\(animals[selectIndex])です")
WheelPickerView(selection: $selectIndex, content: animals)
.frame(width: 200, height: 60)
.clipped()
}
}
}
追記
記事を書いている途中で解決方法を発見しました笑
でも何か副作用があるかもしれないので公式で対応されるまではUIKitで作成したのを使った方がいいかもしれません。
Pickerの高さの+20くらいを設定するとちょうどいい感じになります。
import SwiftUI
struct ContentView: View {
@State var selectIndex: Int = 0
let animals: [String] = ["ライオン", "ニワトリ", "イヌ", "トナカイ", "キツツキ", "モグラ"]
var body: some View {
VStack(alignment: .center, spacing: 50) {
Text("好きな動物は\(animals[selectIndex])です")
Picker("", selection: $selectIndex) {
ForEach(0..<animals.count, id: \.self) { index in
Text(animals[index])
}
}
.pickerStyle(.wheel)
.frame(width: 200, height: 60)
}
}
}
extension UIPickerView {
open override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: 80)
}
}
参考記事