Search code examples
swiftimageswiftuiuisegmentedcontrolpicker

SwiftUI Picker SegmentedStyle Image bad display


I have a simple Picker in SegmentedStyle with two images inside:

@State var selectedIndex = 0

@State var segmentOptions = [
    Image.carFill,
    Image.walking
]
//@State var destination: Destination

var body: some View {
    HStack {
        Picker(selection: $selectedIndex, label: Text("")) {
            segmentOptions[0]
                .tag(0)
            segmentOptions[1]
                .tag(1)
        }.pickerStyle(SegmentedPickerStyle())
        Text("test")
    }
}

First is an Image system from SF Symbol, second is another one I imported from an asset.

The display of the second image stay without padding and in a fill aspectRatio, it doesnt matter about what I put as options. Note it works perfectly while using another PickerStyle (wheel).

I tried following:

segmentOptions[1].aspectRatio(contentMode: .fit).padding()

and

segmentOptions[1].resizable().aspectRatio(contentMode: .fit).padding().frame(width: 20, height: 20, alignment: .center)

And many other combinations but the result is still the same: the second image display without padding and with a fill aspectRatio.

Do you have any idea on how to fix it?

enter image description here


Solution

  • By result of my finding I recommend to resize raster image explicitly to needed size (I used 24 x 24 for 1x) ... or find accepted vector format (probably PDF, but I'm not sure... trying to find some to test, and, btw, custom SW can also be designed)

    Here is why... let start from API declaration

    /// A `PickerStyle` where the options are contained in a segmented control.
    ///
    /// - Note: Only supports segments of type `Label` and `Image`. Passing any
    /// other type of view will result in a visible, but empty, segment.
    @available(iOS 13.0, OSX 10.15, tvOS 13.0, *)
    @available(watchOS, unavailable)
    public struct SegmentedPickerStyle : PickerStyle {
    

    As it is seen only Image works, so any sizeToFit and aspect-like do not work, because they generate View.

    Here is used manually pre-resized PNG image (any graphic designer can create perfect image of needed size, as it used to be for button icons)

    Demo result:

    enter image description here

    Demo code:

    extension Image {
        static var carFill: Image {
            Image(systemName: "car.fill")
        }
        
        static var walking: Image {
            Image("pedestrian_small") // < explicitly resized 1x:24 x 24
        }
    }
    
    struct TestSegmentWithImages: View {
        @State var selectedIndex = 0
    
        @State var segmentOptions = [
            Image.carFill,
            Image.walking
        ]
    
        var body: some View {
            VStack {
                Image("pedestrian") // << original 400 x 400
                    .resizable()
                    .scaledToFit()
                    .frame(width: 48)
                HStack {
                    Picker(selection: $selectedIndex, label: Text("")) {
                        segmentOptions[0]
                            .tag(0)
                        segmentOptions[1]
                            .tag(1)
                    }.pickerStyle(SegmentedPickerStyle())
                    Text("test")
                }
            }
        }
        
    }