swiftuitransitiondeprecation-warningios-animations

How can I update this custom Picker animation and transition to iOS 15?


The code beloew works well up to iOS 15, but now I'm getting the warning 'animation' was deprecated in iOS 15.0: Use withAnimation or animation(_:value:) instead.

Looking around, it appears I should use .animation(_, value: someValue) - that does get rid of the warning, but then the code does not animate properly. I suppose it has to do with the picker being too fast? Or the picker influencing the id of the views?

This is the code that works, but of course, I'd prefer to keep it up-to-date with iOS 15:


struct SamplePickerSwap: View {
    let swapAnimation: Animation = .easeInOut(duration: 0.3333)
    let swapRight: AnyTransition = .asymmetric(
        insertion: .move(edge: .trailing),
        removal: .move(edge: .leading))
    let swapLeft: AnyTransition = .asymmetric(
        insertion: .move(edge: .leading),
        removal: .move(edge: .trailing))
    
    @State private var picker = 0
    @State private var segments = ["Left", "Right"]
    var body: some View {
        
        VStack {
            Picker("", selection: $picker) {
                ForEach(0 ..< segments.count) { index in
                    Text(self.segments[index])
                        .tag(index)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            
            switch picker {
                case 0:
                    Rectangle().fill(Color.green)
                        //.animation(swapAnimation, value: page) //This does not work
                        .animation(swapAnimation) // This is deprecated...
                        .transition(swapLeft)
                case 1:
                    Rectangle().fill(Color.yellow)
                        .animation(swapAnimation)
                        .transition(swapRight)
                default:
                    Rectangle().fill(Color.green)
                        .animation(swapAnimation) //
                        .transition(swapLeft)
            }
            Spacer()
        }
        .padding()
    }
}


I've tried adding another var @State private var page = 0 and changing it with this:

            .onChange(of: picker, perform:  { _ in
                page = picker
            })

and using the iOS animation code of .animation(swapAnimation, value: page) or .animation(swapAnimation, value: picker) but no combination seems to work.


Solution

  • We need to add animation to container (VStack in this case) to make subviews animated, like

        VStack {
            Picker("", selection: $picker) {
                ForEach(0 ..< segments.count) { index in
                    Text(self.segments[index])
                        .tag(index)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
    
            switch picker {
            case 0:
                Rectangle().fill(Color.green)
                    .transition(swapLeft)
            case 1:
                Rectangle().fill(Color.yellow)
                    .transition(swapRight)
            default:
                Rectangle().fill(Color.green)
                    .transition(swapLeft)
            }
            Spacer()
        }
        .animation(swapAnimation, value: picker) // << here !!
    

    Tested with Xcode 13 / iOS 15

    demo