LoginSignup
5
4

More than 1 year has passed since last update.

【SwiftUI】iOS15からWheelPickerStyleが壊れたから自作した

Last updated at Posted at 2022-08-26

はじめに

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

Simulator Screen Recording - iPhone 12 - 2022-08-25 at 22.22.53.gif

追記

記事を書いている途中で解決方法を発見しました笑
でも何か副作用があるかもしれないので公式で対応されるまでは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)
    }
}

Simulator Screen Recording - iPhone 12 - 2022-08-25 at 22.25.21.gif

参考記事

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4