在 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 修飾器的關係讓寬度正確的縮小。
雖然可以使用 clipped 修飾器將 frame 外的部分裁減掉,但這是假象,使用者在滾動中間重疊區域的地方依然是右邊的 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 元件的灰色區域已經不會超過綠色框線,也會正確的反應使用者操作了。
補充說明:網路上的許多解法也許在當時的版本有效,例如 clipped()、labelsHidden()、compositingGroup()、設定 frame()的 minWidth、maxWidth、idealWidth…等,但現在不用再去試了,在 Xcode14 + iOS16.0 全部失效。