如何使 SwiftUI Picker 的段实际上与其内容一样宽,而不是与最宽的段一样宽?

问题描述 投票:0回答:1

在 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()

显示为:

enter image description here

但是,如果我将

toReturn.append("T")
更改为更长的字符串,例如
toReturn.append("Tasks")
,则这些段将变得与最宽的段一样宽,并且实际上不适合其内容:

enter image description here

如何使 SwiftUI Picker 的段实际上与其内容一样宽,而不是与最宽的段一样宽?

ios swift swiftui
1个回答
0
投票

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)
    }
}

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.