解決 Picker 元件的滾輪重疊

在 SwiftUI 中的兩個 Picker 元件平行排列並且以滾輪形式呈現時,滾輪會出現重疊狀況導致使用者無法正確滾動滾輪,程式碼如下。Xcode Version 14.0.1 (14A400) / Project Version 16.0

struct ContentView: View {
    @State private var selectedStart = "南港"
    @State private var selectedEnd = "高雄"
    
    let stationName = ["南港","台北","板橋","桃園","新竹","苗栗","台中","彰化","雲林","嘉義","台南","高雄"]
    
    var body: some View {
        HStack {
            Picker("起點", selection: $selectedStart) {
                ForEach(stationName, id: \.self) { item in
                    Text(item)
                        .border(.red)
                }
            }
            .pickerStyle(.wheel)
            .frame(width: 200)
            
            Picker("終點", selection: $selectedEnd){
                ForEach(stationName, id: \.self) { item in
                    Text(item)
                }
            }
            .pickerStyle(.wheel)
            .frame(width: 200)
        }
        .padding()
        .border(.blue)
    }
}

這段程式碼在右側的預覽畫面會看到中間的灰色區域是重疊的,也就是 Picker 元件並沒有因為 frame 修飾器的關係讓寬度正確的縮小。

截圖 2022-10-16 11.42.49

雖然可以使用 clipped 修飾器將 frame 外的部分裁減掉,但這是假象,使用者在滾動中間重疊區域的地方依然是右邊的 Picker 元件有反應。

截圖 2022-10-16 13.39.29
加上 clipped 修飾器
截圖 2022-10-16 11.44.09
在 frame 後加上 clipped 修飾器雖然灰色區域不重疊,但使用者操作圖示區域依然是右邊 Picker 元件有反應

目前在 Xcode14 要解決這個問題是透過擴增 UIPickerView 元件,並覆寫其中一個屬性。因為 Picker 元件的底層其實還是 UIKit 的 UIPickerView,所以透過 frame 改變元件大小時,要求 UIPickerView 重新計算長寬值即可。

extension UIPickerView {
   open override var intrinsicContentSize: CGSize {
      CGSize(
        width: UIView.noIntrinsicMetric,
        height: super.intrinsicContentSize.height
      )
   }
}

現在將 clipper 修飾器拿掉,可以看到 Picker 元件的灰色區域已經不會超過綠色框線,也會正確的反應使用者操作了。

截圖 2022-10-16 11.48.59

補充說明:網路上的許多解法也許在當時的版本有效,例如 clipped()、labelsHidden()、compositingGroup()、設定 frame()的 minWidth、maxWidth、idealWidth…等,但現在不用再去試了,在 Xcode14 + iOS16.0 全部失效。

發表迴響