SwiftUI does not assist this in the mean time, so that you’d must drop all the way down to UIKit, and set UISegmentedControl.apportionsSegmentWidthsByContent
to true.
If you don’t need any segmented picker to have equal widths, simply use the UIAppearance
APIs,
// put this in onAppear wherever you want it
UISegmentedControl.look().apportionsSegmentWidthsByContent = true
In any other case, you possibly can write your personal UIViewRepresentable
. Right here is an instance:
struct FitWidthSegmenetedPicker: UIViewRepresentable {
let choices: [Selection]
@Binding var choice: Choice
let titleForOption: (Choice) -> String
init(
_ choices: [Selection],
choice: Binding,
titleForOption: @escaping (Choice) -> String = { String(describing: $0) }
) {
self.choices = choices
self._selection = choice
self.titleForOption = titleForOption
}
func makeUIView(context: Context) -> UISegmentedControl {
let segmentedControl = UISegmentedControl()
segmentedControl.apportionsSegmentWidthsByContent = true
segmentedControl.addTarget(context.coordinator, motion: #selector(Coordinator.selectionChanged(_:)), for: .valueChanged)
return segmentedControl
}
func updateUIView(_ uiView: UISegmentedControl, context: Context) {
uiView.removeAllSegments()
for possibility in choices.reversed() {
uiView.insertSegment(withTitle: titleForOption(possibility), at: 0, animated: false)
}
uiView.selectedSegmentIndex = choices.firstIndex(of: choice) ?? 0
context.coordinator.onSelectionChanged = { index in
choice = choices[index]
}
}
func makeCoordinator() -> Coordinator {
.init()
}
@MainActor
class Coordinator: NSObject {
var onSelectionChanged: ((Int) -> Void)?
@objc func selectionChanged(_ sender: UISegmentedControl) {
onSelectionChanged?(sender.selectedSegmentIndex)
}
}
}
Utilization:
struct ContentView: View {
let choices = ["x", "xx", "xxx", "xxxx", "xxxxxxxxxxxx"]
@State personal var choice = "x"
var physique: some View {
FitWidthSegmenetedPicker(choices, choice: $choice)
.fixedSize()
Textual content(choice)
}
}