I am building a Form right know and want to implement a Picker. The Picker shall have a normal Image from my Assets plus the Text. In the selection, it works fine, but without selection, is's a mess:
Code below:
@State private var name = ""
@State private var careTypeName = "Prune"
@State private var careDue = Date.now
@State private var datePickerId: Int = 0
@State private var selectedBonsai = "Juniperus"
@State private var selectedBonsai2 = 0
@Environment(\.dismiss) var dismiss
var body: some View {
NavigationView {
Form {
Section("Choose either a Taskname or pick Careoption") {
TextField("Taskname", text: $name)
Picker("Care option", selection: $careTypeName) {
ForEach(["Prune", "Watering", "Fertilize"], id: \.self) { subject in
Text(subject)
}
}
}
Section("Pick a date for Task") {
DatePicker(selection: $careDue, in: ...Date.now, displayedComponents: .date) {
Text("Select a due date")
}
.id(datePickerId)
.onChange(of: careDue, perform: { _ in
datePickerId += 1
})
}
Section("Select Bonsai:") {
Picker(selection: $selectedBonsai, label: Text("Bonsai")) {
HStack {
Image("d2")
.renderingMode(Image.TemplateRenderingMode.original)
.resizable()
.scaledToFill()
.frame(maxWidth: 60, maxHeight: 35)
.clipShape(RoundedRectangle(cornerRadius: 3))
Text(selectedBonsai)
}
}
}
Button {
dismiss()
} label: {
HStack {
Spacer()
Text("Save Task")
.foregroundColor(Color("buttonColor"))
Spacer()
}
}
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
VStack {
Text("Add Task")
.font(.system(size: 25))
.bold()
.foregroundColor(Color("titleColor"))
}.padding(.leading, 8)
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: {
dismiss()
}, label: {
Text("Cancel")
.foregroundColor(Color("headerButtons"))
.bold()
})
}
}
}
}
}
Did I miss something? Where can I restrict the image-size in the "preview" from the Picker?
Thanks for help :)
If I'm try it with a systemName-Image it works as intended. enter image description here
Tried this as well:
Image(uiImage: UIImage(imageLiteralResourceName: "d2"))
Thanks for help :)
Looking at the UI hierarchy, it appears that SwiftUI doesn't care about resizable
or frame
modifiers for images in the picker. It just translates the picker into a UIButton
, with the image as the button's image, which is displayed using a UIImageView
.
This doesn't seem like something we can control. Perhaps we will be able to do that in a future version of SwiftUI.
A simple solution is to just make a smaller version of the image, so that it fits into the list row.
If you cannot do that for some reason, you can try to mimic how a .menu
picker looks.
LabeledContent("Bonsai") {
HStack {
Image("d2") // putting the image of the currently selected option outside of the picker
// in reality you would do Image(f(selectedBonsai)) where f is a function
// that converts the selected option to an image name
.renderingMode(Image.TemplateRenderingMode.original)
.resizable()
.scaledToFit()
.frame(maxWidth: 60, maxHeight: 35)
.clipShape(RoundedRectangle(cornerRadius: 3))
Menu {
// put the picker inside a menu, so users see the images in the menu
Picker(selection: $selectedBonsai) {
Label {
Text(selectedBonsai)
} icon: {
Image("my_image")
}
.tag("Juniperus")
} label: { }
} label: {
HStack {
Text(selectedBonsai)
Image(systemName: "chevron.up.chevron.down")
}
.tint(.secondary)
.imageScale(.small)
}
}
}