Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Expandable Custom Segmented Picker in SwiftUI

I’m trying to create an expandable segmented picker in SwiftUI, I’ve done this so far :

struct CustomSegmentedPicker: View {
    
    @Binding var preselectedIndex: Int
    
    @State var isExpanded = false
    
    var options: [String]
    let color = Color.orange

    var body: some View {
        HStack {
            ScrollView(.horizontal) {
                HStack(spacing: 4) {
                    ForEach(options.indices, id:\.self) { index in
                        let isSelected = preselectedIndex == index
                        ZStack {
                            Rectangle()
                                .fill(isSelected ? color : .white)
                                .cornerRadius(30)
                                .padding(5)
                                .onTapGesture {
                                    preselectedIndex = index
                                    withAnimation(.easeInOut(duration: 0.5)) {
                                        isExpanded.toggle()
                                    }
                                }
                        }
                        .shadow(color: Color(UIColor.lightGray), radius: 2)
                        .overlay(
                            Text(options[index])
                                .fontWeight(isSelected ? .bold : .regular)
                                .foregroundColor(isSelected ? .white : .black)
                        )
                        .frame(width: 80)
                    }
                }
            }
            .transition(.move(edge: .trailing))
            .frame(width: isExpanded ? 80 : CGFloat(options.count) * 80 + 10, height: 50)
            .background(Color(UIColor.cyan))
            .cornerRadius(30)
            .clipped()
            Spacer()
        }
    }
}

Which gives this result :

GIF showing the result of the expandable picker

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Now, when it contracts, how can I keep showing the item selected and hide the others ? (for the moment, the item on the left is always shown when not expanded)

>Solution :

Nice job. You can add an .offset() to the contents of the ScollView, which shifts it left depending on the selection:

enter image description here

        HStack {
            ScrollView(.horizontal) {
                HStack(spacing: 4) {
                    ForEach(options.indices, id:\.self) { index in
                        let isSelected = preselectedIndex == index
                        ZStack {
                            Rectangle()
                                .fill(isSelected ? color : .white)
                                .cornerRadius(30)
                                .padding(5)
                                .onTapGesture {
                                    preselectedIndex = index
                                    withAnimation(.easeInOut(duration: 0.5)) {
                                        isExpanded.toggle()
                                    }
                                }
                        }
                        .shadow(color: Color(UIColor.lightGray), radius: 2)
                        .overlay(
                            Text(options[index])
                                .fontWeight(isSelected ? .bold : .regular)
                                .foregroundColor(isSelected ? .white : .black)
                        )
                        .frame(width: 80)
                    }
                }
                .offset(x: isExpanded ? CGFloat(-84 * preselectedIndex) : 0) // <<< here
            }
            .transition(.move(edge: .trailing))
            .frame(width: isExpanded ? 80 : CGFloat(options.count) * 80 + 10, height: 50)
            .background(Color(UIColor.cyan))
            .cornerRadius(30)
            .clipped()
            Spacer()
        }
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading