2

Is there a way to create a multiline label in a SwiftUI Picker with a SegementedPickerStyle. I basically would like to create the following:

targetView

But I have not found a way to create a Picker with a multiline label. Is there a way to do this with standard SwiftUI controls? From my research even in UIKit this was a problem.

1 Answer 1

5

System controls are only default controls - we can always implement our own with whichever parameters we need.

Here is simplified demo of how to implement custom picker with any cell content needed.

Note: all constants and parameters can be separated into standalone configuration struct to be used as style, etc.

Used Xcode 13.2 / iOS 15.2

demo

struct TestMyPicker: View {

    @State private var selection: Int?
    let data = [1, 2, 3, 4]
    var body: some View {
        MyPicker(data: data, selection: $selection) { item in
            VStack {
                Text("H\(item)")
                Text("Sub \(item)")
            }.padding(.horizontal, 12)
        }
    }
}

extension Int: Identifiable {      // just for testing purpose
    public var id: Int { self }
}


struct MyPicker<Cell, Data>: View where Cell: View, Data: RandomAccessCollection, Data.Element: Identifiable {
    let data: Data
    @Binding var selection: Data.Element?
    @ViewBuilder let cell: (Data.Element) -> Cell
    @Namespace private var ns

    var body: some View {
        HStack(spacing: 0) {
            ForEach(data) { item in
                cell(item)
                    .foregroundColor(.white)
                    .padding(.horizontal, 8)
                    .overlay(
                        Group {
                            if selection?.id == item.id {
                                RoundedRectangle(cornerRadius: 8).fill(Color.white)
                                    .opacity(0.2)
                                    .matchedGeometryEffect(id: "Marker", in: ns)
                            }
                        }
                    )
                    .onTapGesture {
                        if selection?.id == item.id {
                            selection = nil
                        } else {
                            selection = item
                        }
                    }
            }
        }
        .animation(.linear(duration: 0.25), value: selection?.id)
        .fixedSize(horizontal: false, vertical: true)
        .padding(2)
        .background(RoundedRectangle(cornerRadius: 8).fill(Color.gray))
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

While this would work I would prefer a solution based on the standard SwiftUI Picker, since I then would have to worry less about potential bugs and design. I am guessing you are sure that there is no solution in SwiftUI currently?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.