Image & Text inside picker.

Hi,

I am trying to use a flag image inside a picker like this:

Picker("Title: ", selection: $selection){
            ForEach(datas, id: \.self){ data in
                HStack{
                    Text(data.name)
                    if condition {
                        Image(systemName: "globe")
                    }else {
                        Image(img)
                    }
                }
                .tag(data.name)
                .padding()
            }
        }

All images are loading successfully but only system images are resized correctly. Images loaded from Assets are appearing in their default size. I have tried to size the images with frames, etc but with no luck.

Any idea, help will be much appreciated.

Thanks in advance!

Answered by Claude31 in 826554022

If you use directly Image, it does not work. You have to use the Image built from a resized UIImage. That would be worth a bug report.

Get a solution here: https://www.hackingwithswift.com/forums/swift/remove-or-resize-an-image-when-selecting-an-item-in-a-picker-view/23940

Here is the full code.

Fiat 500e is an image in Assets

struct ContentView: View {
    
    struct Data: Identifiable, Hashable {
        var id = UUID()
        var name: String
        var condition: Bool
    }
    
    @State var selection = "Easy"

    var datas: [Data] = [Data(name: "Easy", condition: true),
                         Data(name: "Medium", condition: false),
                         Data(name: "Hard", condition: true)]
    var myImage: UIImage = UIImage(named: "Fiat 500e") ?? UIImage()
    
    var resizedImage: UIImage {
        return myImage.scalePreservingAspectRatio(targetSize: CGSize(width: 50, height: 25))
    }

    var body: some View {

        Picker("Title: ", selection: $selection) {
            ForEach(datas, id: \.self) { data in
                HStack {
                    Text(data.name)
                    if data.condition {
                        Image(systemName: "globe")
                    } else {
                        Image(uiImage: resizedImage)
                            .resizable()
                            .scaledToFit()
                    }
                    
                }
                .tag(data.name)
                .padding()
            }
        }
    }
}

extension UIImage {
       func scalePreservingAspectRatio(targetSize: CGSize) -> UIImage {
           // Determine the scale factor that preserves aspect ratio
           let widthRatio = targetSize.width / size.width
           let heightRatio = targetSize.height / size.height

           let scaleFactor = min(widthRatio, heightRatio)

           // Compute the new image size that preserves aspect ratio
           let scaledImageSize = CGSize(
               width: size.width * scaleFactor,
               height: size.height * scaleFactor
           )

           // Draw and return the resized UIImage
           let renderer = UIGraphicsImageRenderer(
               size: scaledImageSize
           )

           let scaledImage = renderer.image { _ in
               self.draw(in: CGRect(
                   origin: .zero,
                   size: scaledImageSize
               ))
           }
           return scaledImage
       }
   }

The image displayed in selection is now resized (it was automatically resized in Picker):

In Picker. After selection.

Have you definitely added .resizable() to the Image? Show us some code where you've tried frames etc.

Accepted Answer

If you use directly Image, it does not work. You have to use the Image built from a resized UIImage. That would be worth a bug report.

Get a solution here: https://www.hackingwithswift.com/forums/swift/remove-or-resize-an-image-when-selecting-an-item-in-a-picker-view/23940

Here is the full code.

Fiat 500e is an image in Assets

struct ContentView: View {
    
    struct Data: Identifiable, Hashable {
        var id = UUID()
        var name: String
        var condition: Bool
    }
    
    @State var selection = "Easy"

    var datas: [Data] = [Data(name: "Easy", condition: true),
                         Data(name: "Medium", condition: false),
                         Data(name: "Hard", condition: true)]
    var myImage: UIImage = UIImage(named: "Fiat 500e") ?? UIImage()
    
    var resizedImage: UIImage {
        return myImage.scalePreservingAspectRatio(targetSize: CGSize(width: 50, height: 25))
    }

    var body: some View {

        Picker("Title: ", selection: $selection) {
            ForEach(datas, id: \.self) { data in
                HStack {
                    Text(data.name)
                    if data.condition {
                        Image(systemName: "globe")
                    } else {
                        Image(uiImage: resizedImage)
                            .resizable()
                            .scaledToFit()
                    }
                    
                }
                .tag(data.name)
                .padding()
            }
        }
    }
}

extension UIImage {
       func scalePreservingAspectRatio(targetSize: CGSize) -> UIImage {
           // Determine the scale factor that preserves aspect ratio
           let widthRatio = targetSize.width / size.width
           let heightRatio = targetSize.height / size.height

           let scaleFactor = min(widthRatio, heightRatio)

           // Compute the new image size that preserves aspect ratio
           let scaledImageSize = CGSize(
               width: size.width * scaleFactor,
               height: size.height * scaleFactor
           )

           // Draw and return the resized UIImage
           let renderer = UIGraphicsImageRenderer(
               size: scaledImageSize
           )

           let scaledImage = renderer.image { _ in
               self.draw(in: CGRect(
                   origin: .zero,
                   size: scaledImageSize
               ))
           }
           return scaledImage
       }
   }

The image displayed in selection is now resized (it was automatically resized in Picker):

In Picker. After selection.

Image & Text inside picker.
 
 
Q