SwiftUI Picker image problem

I have a simple configuration in which a picker line contains an image and a text.

When I use my own images, the image only shows properly in the first view, showing the current selection.

when I activate the picker, showing the list of items, the images are white.

It works properly if I use systemName: images instead.

What am I doing wrong ?


Picker(selection: $selectedWorkout, label: Text("Workout")) {

ForEach(wds.workoutList, id: \.id) { workout in

HStack {

Image("\(workout.type.description)")

.resizable()

.aspectRatio(self.aspect, contentMode: .fill)

.frame(width: 30, height: 30, alignment: .center)

Text("\(workout.type.description) (\(workout.distance)km) du \(workout.date.substring(to: 16))")

}

}

}

Replies

If you put the images in xcassets, it works.


So, it is probably the way to define the image name that causes problem.

The following should work as well (looks like a limitation, not to call it a bug, of SwiftUI)


Picker(selection: $selectedWorkout, label: Text("Workout")) {
    ForEach(wds.workoutList, id: \.id) { workout in
        HStack {
            //  Image("\(workout.type.description)")
               Image(uiImage: UIImage(named: "\(workout.type.description)")!)     // Take care of the forced unwrap though
                .resizable()
                .aspectRatio(self.aspect, contentMode: .fill)
                .frame(width: 30, height: 30, alignment: .center)
            Text("\(workout.type.description) (\(workout.distance)km) du \(workout.date.substring(to: 16))")
        }
    }
}

Tried to add Bundle.main to the Image() parameters, does not work.


See in depth discussion here:

https://stackoverflow.com/questions/56992666/swiftui-no-image-named-was-found-in-main-bundle

Thanks for the reply.

I tested your suggestion, but I get the same issue.

The image is properly rendered in the picker view showing the selected choice.

The problem is only in the second view showing all the items to select.

I don't understand your point.


What is the second view ?


Your OP was about:

when I activate the picker, showing the list of items, the images are white.


In new post:

The image is properly rendered in the picker view showing the selected choice.

Does it work now when putting the image in xcassets or calling Image(named:) ?

Wasn't it the initial question ?


If so, you should close this thread and start a new one, explaining the new question in detail.

When you click on the picker, it brings second view with all the items we can select from.

when your are done selecting, this view closes and you see the selected item in the parent view.

The image is rendered correctly only in the parent view.


I attached 2 images to show (I hope they will be visible)


No, as you know, no image show on forum.


Your question is not clear at all:

When you click on the picker, it brings second view

What is this second view ?

you see the selected item in the parent view.

What is this parent view ?


Please show code and tell what objects you speak about. That may be clear for you but not at all for others.


And once again, as the question of image not showing is solved, close this thread on the correct answer and open a new one with complete details.

Sorry I am very new to SwiftUI and I do not understand how this second view is created, maybe of NavigationView.

I thought maybe only the Picker code had some importance in my problem.

Here is the full code


import SwiftUI

import HealthKit


extension String {

func index(from: Int) -> Index {

return self.index(startIndex, offsetBy: from)

}


func substring(from: Int) -> String {

let fromIndex = index(from: from)

return String(self[fromIndex...])

}


func substring(to: Int) -> String {

let toIndex = index(from: to)

return String(self[..<toIndex])

}


func substring(with r: Range<Int>) -> String {

let startIndex = index(from: r.lowerBound)

let endIndex = index(from: r.upperBound)

return String(self[startIndex..<endIndex])

}

}


struct ProgressBar: View {

@ObservedObject var wds = WorkoutDataStore()

var body: some View {

GeometryReader { geometry in

ZStack(alignment: .leading) {

Rectangle().frame(width: geometry.size.width , height: geometry.size.height)

.opacity(0.3)

.foregroundColor(Color(UIColor.systemTeal))

Rectangle().frame(width: min(CGFloat(self.wds.progress)*geometry.size.width, geometry.size.width), height: geometry.size.height)

.foregroundColor(Color(UIColor.systemBlue))

.animation(.linear)

}.cornerRadius(45.0)

}

}

}


struct ContentView: View {

@ObservedObject var wds = WorkoutDataStore()

@State var selectedWorkout = 0

@State var lastSelection = 0

lazy var dateFormatter:DateFormatter = {

let formatter = DateFormatter()

formatter.dateFormat = "yyyy-MM-dd HH:mm"

formatter.timeZone = TimeZone.current

return formatter

}()

let aspect: CGSize = CGSize(width: 234, height: 150)

var body: some View {

NavigationView {

ZStack {

Form {

Section(header: Text("\(self.wds.count) Workouts to choose from")){

Picker(selection: $selectedWorkout, label: Text("Workout")) {

ForEach(wds.workoutList, id: \.id) { workout in

HStack {

Image(uiImage: UIImage(named: "\(workout.type.description)")!)

.resizable()

.aspectRatio(self.aspect, contentMode: .fill)

.frame(width: 30, height: 30, alignment: .center)

Text("\(workout.type.description) (\(workout.distance)km) du \(workout.date.substring(to: 16))")

}

}

}

ProgressBar(wds: wds).frame(height: 20)

Button(action: {

self.sendWorkout(selected: self.selectedWorkout)

}) {

HStack {

Image(systemName: self.wds.syncError ? "exclamationmark.icloud.fill" : ( self.wds.synching ? "ellipses.bubble" : (self.wds.syncCompleted && (self.lastSelection == self.selectedWorkout) ? "hand.thumbsup" : "icloud.and.arrow.up")))

.font(.title)

Text(self.wds.syncError ? "Error" : ( self.wds.synching ? "Processing" : (self.wds.syncCompleted && (self.lastSelection == self.selectedWorkout) ? "Done" : "Sync")))

.fontWeight(.semibold)

.font(.title)

}

.frame(minWidth: 0, maxWidth: .infinity)

.padding()

.foregroundColor(.white)

.background(self.wds.syncError ? Color.red : ( self.wds.synching ? Color.yellow : (self.wds.syncCompleted && (self.lastSelection == self.selectedWorkout) ? .green : .blue)))

.cornerRadius(40)

}.disabled(self.wds.synching)

Button(action: {

self.refresh()

}) {

HStack {

Text("refresh")

.fontWeight(.semibold)

.font(.title)

}

.frame(minWidth: 0, maxWidth: .infinity)

.padding()

.foregroundColor(Color.white)

.background(Color.green)

.cornerRadius(40)

}

}

}


// The Custom Popup is on top of the screen

if self.wds.syncError {

// But it will not show unless this variable is true

ZStack {

Color.black.opacity(0.4)

.edgesIgnoringSafeArea(.vertical)

// This VStack is the popup

VStack(spacing: 20) {

Text("Popup")

.bold().padding()

.frame(maxWidth: .infinity)

.background(Color.orange)

.foregroundColor(Color.white)

Text("\(self.wds.failure)").frame(maxWidth: .infinity).background(Color.white).foregroundColor(Color.red)

Button(action: {self.wds.syncError = false})

{

Text("Close")

}.frame(minWidth: 0, maxWidth: .infinity)

.padding()

.foregroundColor(Color.white)

.background(Color.blue)

}

.frame(width: 300, height: 200)

.background(Color.white)

.cornerRadius(20).shadow(radius: 20)

}

}

}.navigationBarTitle("Settings")

}

}

func refresh()

{

self.wds.reloadWorkouts()

}

func sendWorkout(selected: Int)

{

self.lastSelection = selected

self.wds.syncWorkout(selected: selected)

}

}


struct WorkoutRow: View {

var details: WorkoutDetails

var body: some View {

Text("\(String(details.type.rawValue)) of \(details.date)")

}

}


struct ContentView_Previews: PreviewProvider {

static var previews: some View {

ContentView()

}

}

Cannot test, WorkoutDataStore is undefined.

There is probably another file where this class is defined. Please provide it.


But please, close this thread and create a new one. It is not good to have multiple questions in an ever ending thread.

I found the answer to my problem.

In order for the image to render properly in the picker, you need to

add this option (renderingMode) otherwise the image is all white


NavigationView {

ZStack {

Form {

Section(header: Text("Sélectionnez parmis les \(self.wds.workoutList.count) derniers exercices")){

Picker(selection: $selectedWorkout, label: Text("Workout")) {

ForEach(wds.workoutList, id: \.id) { workout in

HStack {

Image(uiImage: UIImage(named: "\(workout.type.description)")!)

-------------> .renderingMode(Image.TemplateRenderingMode.original) // important

.resizable()

.aspectRatio(self.aspect, contentMode: .fill)

.frame(width: 30, height: 30, alignment: .center)

Text("\(workout.type.description) (\(workout.distance)km) du \(workout.date.substring(to: 16))")

}

}

}

I am having the same issue when using a picker in a form.


Supporting Images

https://i.stack.imgur.com/nzIyW.jpg

https://imgur.com/a/lOgItMH


From left to right:

  1. Image(uiImage: ) displayed in a form section in a HStack
  2. Image in a Picker with Image(uiImage: )
  3. Image in a Picker with Image(systemImage: )


You can see that in 2 & 3 it automatically applies a tint/mask (maskColor) of black (when using non dark mode and tint/mask of white when in dark mode).


This must be default behaviour of SwiftUI to add a mask to any image inside the view shown when going to the selection list of a picker in a form.


I am unable to work out how to remove this mask/tint off the image and display it in colour.



Section(header: Text("Wind")) {

                    Picker("", selection: $addAdjustmenViewModel.selectedWindDirection) {
                        ForEach(0..<addadjustmenviewmodel.winddirection.count, id:="" \.self)="" {<br="">                            WindPickerView(direction: self.addAdjustmenViewModel.windDirection[$0]).tag($0)
                        }
                        .navigationBarTitle("Wind Direction")
                    }.navigationBarTitle(navigationTitle)
}


import SwiftUI
import UIKit

struct WindPickerView: View {
    var direction: String = "N"
    private var windImage: UIImage!
   
    init(direction: String) {
        self.direction = direction
        windImage = LocalImageManager.sharedInstance.windDirectionImages(direction: self.direction)
        //print("end init")
    }
   
    var body: some View {
        HStack {
            Image(uiImage: windImage).resizable().frame(width: 32, height: 32, alignment: .center).padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 0))
            Spacer()
            Text(direction)
            .padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 8))
        }
    }
}

struct WindPickerView_Previews: PreviewProvider {
    static var previews: some View {
        WindPickerView(direction: "N")
    }
}


Thanks for feedback. I could not get there as I was missing file to test the code…

The option to put in xcAssets has probably a similar effect, automatically.


That was in fact the same with UIKit, you have to set this mode otherwise image is transparent !


Don't forget to close the thread.