'SwiftUI overlay dropdown without exceeding bounds of parentView

I want to create a dropdown component in SwiftUI that overlays over other random components but at the same time to not exceed the bounds of the parent view that contains all the components. I have tried 2 versions so far. In the first attempt I created the dropdown within an overlay modifier. But it exceeds the bounds. Here is the code for this:

var body: some View {
        HStack(spacing: 8) {
            Text("TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST")
                .frame(width: preTextWidth, alignment: .leading)
            HStack {
                Text(optionChosen ? input : "Choose an option")
                    .fontWeight(.bold)
                Image(systemName: expand ? "chevron.up" : "chevron.down")
                    .resizable()
                    .frame(width: 14, height: 6)
            }
            .padding()
            .background(isEnabled ? cellColor : .gray)
            .cornerRadius(15)
            .onTapGesture {
                if isEnabled {
                    self.expand.toggle()
                }
            }
            .overlay(
                ZStack{
                    if expand {
                        Spacer().frame(height: 30)
                        VStack(alignment: .center) {
                        
                        ForEach(dropDownList, id: \.self) { text in
                            Button(action: {
                                self.expand.toggle()
                                optionChosen = true
                                input = text
                                onSelectedInput(text)
                            }) {
                                Text(text)
                                    .padding(10)
                                    .foregroundColor(Color.black)
                            }
                            Divider()
                        }
                    }
                    .background(cellColor)
                    .cornerRadius(15)
                }
            }.frame(width: 200).animation(.spring(), value: expand)
            , alignment: .topLeading)
    }
}`

Here is the result:

Here is the 2nd attempt and the problem is that the dropdown doesn't come as an overlay over the other components and pushes them.

var body: some View {
    HStack(alignment: .top) {
        Text("TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST")
            .frame(width: preTextWidth, alignment: .leading)
        Spacer()
        VStack {
            VStack(spacing: 8) {
                HStack {
                    Text(optionChosen ? input : "Choose an option")
                        .fontWeight(.bold)
                    Image(systemName: expand ? "chevron.up" : "chevron.down")
                        .resizable()
                        .frame(width: 14, height: 6)
                }
                .background(isEnabled ? .clear : .gray)
                .onTapGesture {
                    if isEnabled {
                        self.expand.toggle()
                    }
                }
                if expand {
                    ForEach(dropDownList, id: \.self) { text in
                        Button(action: {
                            self.expand.toggle()
                            optionChosen = true
                            input = text
                            onSelectedInput(text)
                        }) {
                            Text(text)
                                .padding(10)
                        }.foregroundColor(.black)
                        
                        Divider()
                    }
                }
            }
            .padding()
            .background(cellColor)
            .cornerRadius(15)
            .animation(.spring(), value: expand)
        }
    }
}
}

enter image description here



Solution 1:[1]

First the design you are trying to mimic is somewhat similar to web/Android. Doing it in iOS way:-

  • You can push a view controller containing all your options.

-OR-

  • You can have a PickerView with pickerStyle(.wheel) which will Automatically manage its bounds.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Suraj Mirajkar