🩰
橫向並排 Picker - SwiftUI
用 SwiftUI 做多選擇的 Picker 的時候發現和 UIKit 不一樣,必須要透過自行建立多個 Pickers 後用 HStack 包起來才可以達成,但是這時候會有排版上的問題。
如下圖一樣,元件會直接往左右凸出去:
import SwiftUI
struct ContentView: View {
@State var leftSelectedIndex = 0
@State var rightSelectedIndex = 0
var body: some View {
HStack(spacing: 0) {
// 左 Picker
Picker("test", selection: $leftSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
// 右 Picker
Picker("test", selection: $rightSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewLayout(.fixed(width: 500, height: 300))
}
}
解法
1. 指定寬度
首先用 GeometryReader 把 HStack 包起來,讓 Pickers 能夠取得 UI 的寬度並設定
GeometryReader { geometry in
HStack { /* ... */ }
}
在 Picker 加上 .frame()
這個 modifier 來設定寬高
Picker("test", selection: $leftSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
// 設定寬高
.frame(maxWidth: geometry.size.width / 2, maxHeight: geometry.size.height)
Picker("test", selection: $rightSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
// 設定寬高
.frame(maxWidth: geometry.size.width / 2, maxHeight: geometry.size.height)
這時候大小雖然設定正確了,但是發現正中間竟然重疊了:
2. 設定裁切
這時候只要加上 .clipped()
這個 modifier 就可以讓 UI 只繪製到指定的邊界以內:
Picker("test", selection: $leftSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
.frame(maxWidth: geometry.size.width / 2, maxHeight: geometry.size.height)
// 設定裁切
.clipped()
Picker("test", selection: $rightSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
.frame(maxWidth: geometry.size.width / 2, maxHeight: geometry.size.height)
// 設定裁切
.clipped()
成果
最終的程式碼
import SwiftUI
struct ContentView: View {
@State var leftSelectedIndex = 0
@State var rightSelectedIndex = 0
var body: some View {
GeometryReader { geometry in
HStack(spacing: 0) {
Picker("test", selection: $leftSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
.frame(maxWidth: geometry.size.width / 2, maxHeight: geometry.size.height)
.clipped()
Picker("test", selection: $rightSelectedIndex) {
ForEach(1..<13) { item in
Text("\(item)")
}
}
.pickerStyle(.wheel)
.frame(maxWidth: geometry.size.width / 2, maxHeight: geometry.size.height)
.clipped()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewLayout(.fixed(width: 500, height: 300))
}
}
Discussion