Search code examples
swiftuisf-symbols

Using SwiftUI SegmentedControl with SF Symbols produces odd behavior


I would like to use SF Symbols in a SegmentedControl in SwiftUI. Copy this code into a project and watch what happens. There is no good way to explain the behavior. You have to see it for yourself.

import SwiftUI

struct ContentView : View {
    @State private var favoriteColor = 0

    var body: some View {
        VStack {
            SegmentedControl(selection: $favoriteColor) {
                Image(systemName: "hammer.fill").tag(0)
                Image(systemName: "house.fill").tag(1)
                Image(systemName: "desktopcomputer").tag(2)
                Image(systemName: "cart.fill").tag(3)
                Image(systemName: "phone.arrow.right.fill").tag(4)
                Image(systemName: "wand.and.rays").tag(5)
                Image(systemName: "slider.horizontal.3").tag(6)
            }
            Text("Value: \(favoriteColor)")
        }
    }
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

If anyone figures this out please provide an answer or an explanation.


Solution

  • Update

    In beta 5 the problem has gone away! Workaround no longer necessary. Also, SegmentedControl has been replaced by Picker:

    Picker(selection: $selectedSegment, label: EmptyView()) {
        Image(systemName: "hammer.fill").tag(0)
        Image(systemName: "house.fill").tag(1)
        Image(systemName: "desktopcomputer").tag(2)
        Image(systemName: "cart.fill").tag(3)
        Image(systemName: "photo").tag(4)
        Image(systemName: "wand.and.rays").tag(5)
        Image(systemName: "slider.horizontal.3").tag(6)
    }.pickerStyle(SegmentedPickerStyle())
    

    Workaround Beta 4 and previous versions

    Yeap, it's a bug. Until it gets fixed, here's a workaround. You basically encapsulate the segment in a separate view, and the problem goes away:

    struct TabItem: View {
        let image: String
        let tag: Int
    
        var body: some View {
            Image(systemName: image).tag(tag)
        }
    }
    
    struct ContentView : View {
        @State private var favoriteColor = 0
    
        var body: some View {
            VStack {
                SegmentedControl(selection: $favoriteColor) {
                    TabItem(image: "hammer.fill", tag: 0)
                    TabItem(image: "house.fill", tag: 1)
                    TabItem(image: "desktopcomputer", tag: 2)
                    TabItem(image: "cart.fill", tag: 3)
                    TabItem(image: "phone.arrow.right.fill", tag: 4)
                    TabItem(image: "wand.and.rays", tag: 5)
                    TabItem(image: "slider.horizontal.3", tag: 6)
                }
                Text("Value: \(favoriteColor)")
            }
        }
    }