在 SwiftUI 中,我有以下内容:
func segments() -> [String] {
var toReturn = Calendar.current.veryShortWeekdaySymbols
toReturn.append("T")
return toReturn
}
Picker("Day of week?", selection: $selectedDay) {
ForEach(segments(), id: \.self) {
Text($0)
.scaledToFit()
}
}
.pickerStyle(.segmented)
.fixedSize()
显示为:
但是,如果我将
toReturn.append("T")
更改为更长的字符串,例如 toReturn.append("Tasks")
,则这些段将变得与最宽的段一样宽,并且实际上不适合其内容:
如何使 SwiftUI Picker 的段实际上与其内容一样宽,而不是与最宽的段一样宽?
SwiftUI 目前不支持此功能,因此您必须下拉至 UIKit,并将
UISegmentedControl.apportionsSegmentWidthsByContent
设置为 true。
如果您不希望任何分段选择器具有相同的宽度,只需使用
UIAppearance
API,
// put this in onAppear wherever you need it
UISegmentedControl.appearance().apportionsSegmentWidthsByContent = true
否则,您可以编写自己的
UIViewRepresentable
。这是一个例子:
struct FitWidthSegmenetedPicker<Selection: Hashable>: UIViewRepresentable {
let options: [Selection]
@Binding var selection: Selection
let titleForOption: (Selection) -> String
init(
_ options: [Selection],
selection: Binding<Selection>,
titleForOption: @escaping (Selection) -> String = { String(describing: $0) }
) {
self.options = options
self._selection = selection
self.titleForOption = titleForOption
}
func makeUIView(context: Context) -> UISegmentedControl {
let segmentedControl = UISegmentedControl()
segmentedControl.apportionsSegmentWidthsByContent = true
segmentedControl.addTarget(context.coordinator, action: #selector(Coordinator.selectionChanged(_:)), for: .valueChanged)
return segmentedControl
}
func updateUIView(_ uiView: UISegmentedControl, context: Context) {
uiView.removeAllSegments()
for option in options.reversed() {
uiView.insertSegment(withTitle: titleForOption(option), at: 0, animated: false)
}
uiView.selectedSegmentIndex = options.firstIndex(of: selection) ?? 0
context.coordinator.onSelectionChanged = { index in
selection = options[index]
}
}
func makeCoordinator() -> Coordinator {
.init()
}
@MainActor
class Coordinator: NSObject {
var onSelectionChanged: ((Int) -> Void)?
@objc func selectionChanged(_ sender: UISegmentedControl) {
onSelectionChanged?(sender.selectedSegmentIndex)
}
}
}
用途:
struct ContentView: View {
let options = ["x", "xx", "xxx", "xxxx", "xxxxxxxxxxxx"]
@State private var selection = "x"
var body: some View {
FitWidthSegmenetedPicker(options, selection: $selection)
.fixedSize()
Text(selection)
}
}