swiftuiios13segmentedcontrol

SwiftUI Segmented Control selected segment text animation on view refresh


I am experiencing the following animation of the text in the selected segment of Segmented Controls when the View is refreshed after changing some other data in the View:

segmented control text animation

Is this a bug/feature or is there a way to eliminate this behaviour?

This is the code to reproduce the effect:

import SwiftUI

struct ContentView: View {
    let colorNames1 = ["Red", "Green", "Blue"]
    @State private var color1 = 0

    let colorNames2 = ["Yellow", "Purple", "Orange"]
    @State private var color2 = 0

    var body: some View {
        VStack {
            VStack {
                Picker(selection: $color1, label: Text("Color")) {
                    ForEach(0..<3, id: \.self) { index in
                        Text(self.colorNames1[index]).tag(index)
                    }
                }.pickerStyle(SegmentedPickerStyle())

                Text("Color 1: \(color1)")
            }
            .padding()

            VStack {
                Picker(selection: $color2, label: Text("Color")) {
                    ForEach(0..<3, id: \.self) { index in
                        Text(self.colorNames2[index]).tag(index)
                    }
                }.pickerStyle(SegmentedPickerStyle())

                Text("Color 2: \(color2)")
            }
            .padding()
        }
    }
}

This was run under iOS 13.4 / Xcode 11.4


Solution

  • rearrange you code base ... (this helps SwiftUI to "refresh" only necessary Views)

    import SwiftUI
    
    struct ContentView: View {
        let colorNames1 = ["Red", "Green", "Blue"]
        @State private var color1 = 0
    
        let colorNames2 = ["Yellow", "Purple", "Orange"]
        @State private var color2 = 0
    
        var body: some View {
            VStack {
                MyPicker(colorNames: colorNames1, color: $color1)
                .padding()
    
                MyPicker(colorNames: colorNames2, color: $color2)
                .padding()
            }
        }
    }
    
    struct MyPicker: View {
        let colorNames: [String]
        @Binding var color: Int
        var body: some View {
            VStack {
                Picker(selection: $color, label: Text("Color")) {
                    ForEach(0..<colorNames.count) { index in
                        Text(self.colorNames[index]).tag(index)
                    }
                }.pickerStyle(SegmentedPickerStyle())
    
                Text("Color 1: \(color)")
            }
        }
    }
    
    struct ContetView_Preview: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }
    

    result

    enter image description here