Search code examples
swiftuipicker

SwiftUI: Add animation to Picker without adding it to the values


I'm trying to animate the hiding/showing of a picker based on a toggle. If true or false, I would like the picker to easeInOut.

I've tried adding the .animation(Animation.easeInOut(duration: 0.5)) to the picker itself or the HStack the picker is in, but both add the animation to values inside the picker and when scrolling through the values the application to crashes.

        HStack {
            if showPicker {
                Picker(selection: $selected.value, label: Text(selected.type)) {
                    ForEach(digits, id: \.self) { d in
                        Text("\(d)")
                    }
                }
                .frame(width: 40)
            }
        }
        .animation(Animation.easeInOut(duration: 2))

            if showPicker {
                Picker(selection: $selected.value, label: Text(selected.type)) {
                    ForEach(digits, id: \.self) { d in
                        Text("\(d)")
                    }
                }
                .frame(width: 40)
                .animation(Animation.easeInOut(duration: 0.5))
            }

Both options do animate the hiding/showing the picker, but it also animates scrolling through the values in the picker, which causes it to crash.

Any help would be appreciated.

Thank you


Solution

  • About your first approach, putting animation on HStack. Never do that. According to the comments in the declaration file:

    Use this modifier on leaf views rather than container views. The animation applies to all child views within this view; calling animation(_:) on a container view can lead to unbounded scope.

    I tried your second approach (filling the missing bits from your post), and it won't crash. Maybe you can update your question with a fully reproducible example.

    Changed animation to explicit, so other parameters are not affected:

    struct PickerStackOverflow: View {
        @State private var showPicker = true
        @State private var value: Int = 1
    
        let digits: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
    
        var body: some View {
            VStack {
                Text("Selected \(value)")
    
                HStack {
                    if showPicker {
                        Picker(selection: $value, label: Text("Label")) {
                            ForEach(digits, id: \.self) { d in
                                Text("\(d)")
                            }
                        }
                        .frame(width: 40)
                    }
                }
    
    
                Button("Tap Me") {
                    withAnimation(Animation.easeInOut(duration: 2)) {
                        self.showPicker.toggle()
                    }
    
                }
            }
    
        }
    }