How to customize picker page selection - swiftui

I have a standard picker in a list, customized in dark colors.
When I tap on the picker, it opens the page with the choices, but the background is white, and I would like it to be black.
Didn't succeed to find the appropriate settings :(
Thanks for your help
My code :
import SwiftUI
let choices = ["red", "blue", "yellow"]
struct test4: View {
#State private var myColor: String = choices[0]
var body: some View {
VStack {
List {
Picker(selection: $myColor, label: Text("Type")) {
ForEach(choices, id: \.self) { col in
Text(col).foregroundColor(Color.gray)
}
}
.listRowBackground(Color.row)
}
}
.background(Color.black)
}
}
Page with the picker
Picker selection

Use instead preferred color scheme, like
VStack {
// List here ...
}
//.background(Color.black)
.preferredColorScheme(.dark) // << use this !!

Related

listRowBackground removes selection style

When using listRowBackground on a SwiftUI List there is no longer any highlighting of the selected item. Using a ButtonStyle for the NavigationLink does not work either.
Are there any sane workaround for this?
Example code:
struct ContentView: View {
struct ContentSection: Identifiable {
let id = UUID()
let title: String
let items: [String]
}
var sections = [
ContentSection(title: "Lorem", items: ["Dolor", "Sit", "Amed"]),
ContentSection(title: "Ipsum", items: ["Consectetur", "Adipiscing", "Elit"])
]
var body: some View {
NavigationView {
List {
ForEach(sections) { section in
Section {
ForEach(section.items, id: \.self) { item in
NavigationLink(destination: Text(item)) {
Text(item)
}
.listRowBackground(Color.orange.ignoresSafeArea())
}
} header: {
Text(section.title)
}
}
}
.listStyle(GroupedListStyle())
}
}
}
Although it is not documented in Apple's documentation, setting a .listRowBackground will wisely remove selection behaviour. What should happen if you set a background of Color.grey which matches the default selection color? Should Apple pick a different color now? How can they be sure the contrast is high enough for the user to tell if the selection is active?
Fortunately you can implement your own selection behaviour using List(selection:, content:) and then comparing the item being rendered in ForEach with the current selected item and changing the background yourself:
struct ContentView: View {
#State var selection: Int?
var body: some View {
List(selection: $selection) {
ForEach(1...5, id: \.self) { i in
Text(i, format: .number)
.listRowBackground(i == selection ? Color.red.opacity(0.5) : .white)
.tag(i)
}
}
}
}
Here it is in action:

Can I set the text color of individual items in a SwiftUI Segmented Picker?

I have a segmented picker in SwiftUI. I'd like each element in the picker to have its own color.
I've tried this:
struct ContentView: View {
#State private var selectedColorIndex = 0
var body: some View {
VStack {
Picker("Favorite Color", selection: $selectedColorIndex, content: {
Text("Red").foregroundColor(.red).tag(0)
Text("Green").tag(1).foregroundColor(.green)
Text("Blue").tag(2).foregroundColor(.blue)
})
.pickerStyle(.segmented)
Text("Selected color: \(selectedColorIndex)")
}
}
}
but the items in the picker don't change color. I find this strange, since items are just simple Text views.....

swiftui 2.0 Image Gallery onTapgesture only shows the first image in the array

I am creating a reusable gallery view for an app and am having difficulties when any picture is tapped it suppose to become full screen but only the first picture in the array is shown every time no matter the picture tapped. Below is my code, thanks.
import SwiftUI
struct ReusableGalleryView: View {
let greenappData: GreenAppNews
let gridLayout: [GridItem] = Array(repeating: GridItem(.flexible()), count: 3)
#State private var fullscreen = false
#State private var isPresented = false
var body: some View {
VStack{
ScrollView{
LazyVGrid(columns: gridLayout, spacing: 3) {
ForEach(greenappData.GreenAppGallery, id: \.self) { item in
Image(item)
.resizable()
.frame(width: UIScreen.main.bounds.width/3, height: 150)
.onTapGesture {
self.isPresented.toggle()
print(" tapping number")
}
.fullScreenCover(isPresented: $isPresented) {
FullScreenModalView( imageFiller: item)
}
.background(Color.gray.opacity(0.5))
}
}
.padding(.horizontal)
}
}
}
}
This is an example of the json data:
{
"id" : "1",
"GreenAppGallery" : [
"Picture-1",
"Picture-2",
"Picture-3",
"Picture-4",
"Picture-5",
"Picture-6",
"Picture-7",
"Picture-8",
"Picture-9",
"Picture-10"
]
},
fullScreenCover, like sheet tends to create this type of behavior in iOS 14 when using isPresented:.
To fix it, you can change to the fullScreenCover(item: ) form.
Not having all of your code, I'm not able to give you an exact version of what it'll look like, but the gist is this:
Remove your isPresented variable
Replace it with a presentedItem variable that will be an optional. Probably a datatype that is in your gallery. Note that it has to conform to Identifiable (meaning it has to have an id property).
Instead of toggling isPresented, set presentedItem to item
Use fullScreenCover(item: ) { presentedItem in FullScreenModalView( imageFiller: presentedItem) } and pass it your presentedItem variable
Move the fullScreenCover so that it's attached to the ForEach loop rather than the Image
Using this system, you should see it respond to the correct item.
Here's another one of my answers that covers this with sheet: #State var not updated as expected in LazyVGrid

SwiftUI: Picker content does not display when selected in a list

I am trying to make a list of selectionable rows in Swift UI, the rows including a Picker. Everything works fine, except that the content of the Picker disappears when selected, see attached screenshot (but is actually visible when the window of the app is not active (i.e. when I click on another window))
I tried everything I could think of, I could not solve this issue. Below a minimal code to reproduce the problem. Anyone has any idea, how to get around this problem
SelectionList.swift
struct SelectionList: View {
#State var dudes: [String] = ["Tim", "Craig", "Phil"]
#State var selectedRow = Set<String>()
var body: some View {
return List(selection: $selectedRow) {
ForEach(self.dudes, id: \.self) { item in
SelectionRow()
}
}
}
}
SelectionRow.swift
struct SelectionRow: View {
#State var selectedFruit = 0
let fruits = ["Apples", "Oranges", "Bananas", "Pears"]
var body: some View {
Picker(selection: self.$selectedFruit, label: EmptyView()) {
ForEach(0 ..< fruits.count, id: \.self) {
Text(self.fruits[$0])
}
}
}
}

How to Hide Keyboard in SwiftUI Form Containing Picker?

I have a SwiftUI Form that contains a Picker, a TextField, and a Text:
struct ContentView: View {
var body: some View {
Form {
Section {
Picker(selection: $selection, label: label) {
// Code to populate picker
}.pickerStyle(SegmentedPickerStyle())
HStack {
TextField(title, text: $text)
Text(text)
}
}
}
}
}
The code above results in the following UI:
I am able to easily select the second item in the picker, as shown below:
Below, you can see that I am able to initiate text entry by tapping on the TextField:
In order to dismiss the keyboard when the Picker value is updated, a Binding was added, which can be seen in the following code block:
Picker(selection: Binding(get: {
// Code to get selected segment
}, set: { (index) in
// Code to set selected segment
self.endEditing()
}), label: label) {
// Code to populate picker
}
The call to self.endEditing() is provided in the following method:
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
The following screenshot displays that selecting a different segment of the Picker dismisses the keyboard:
Up to this point, everything works as expected. However, I would like to dismiss the keyboard when tapping anywhere outside of the TextField since I am unable to figure out how to dismiss the keyboard when dragging the Form's containing scroll view.
I attempted to add the following implementation to dismiss the keyboard when tapping on the Form:
Form {
Section {
// Picker
HStack {
// TextField
// Text
}
}
}.onTapGesture {
self.endEditing()
}
Below, the following two screenshot displays that the TextField is able to become the first responder and display the keyboard. The keyboard is then successfully dismissed when tapping outside of the TextField:
However, the keyboard will not dismiss when attempting to select a different segment of the `Picker. In fact, I cannot select a different segment, even after the keyboard has been dismissed. I presume that a different segment cannot be selected because the tap gesture attached to the form is preventing the selection.
The following screenshot shows the result of attempting to select the second value in the Picker while the keyboard is shown and the tap gesture is implemented:
What can I do to allow selections of the Picker's segments while allowing the keyboard to be dismissed when tapping outside of the TextField?
import SwiftUI
struct ContentView: View {
#State private var tipPercentage = 2
let tipPercentages = [10, 15, 20, 25, 0]
#State var text = ""
#State var isEdited = false
var body: some View {
Form {
Section {
Picker("Tip percentage", selection: $tipPercentage) {
ForEach(0 ..< tipPercentages.count) {
Text("\(self.tipPercentages[$0])%")
}
}
.pickerStyle(SegmentedPickerStyle())
HStack {
TextField("Amount", text: $text, onEditingChanged: { isEdited in
self.isEdited = isEdited
}).keyboardType(.numberPad)
}
}
}.gesture(TapGesture().onEnded({
UIApplication.shared.windows.first{$0.isKeyWindow }?.endEditing(true)
}), including: isEdited ? .all : .none)
}
}
Form's tap gesture (to finish editing by tap anywhere) is enabled only if text field isEdited == true
Once isEdited == false, your picker works as before.
You could place all of your code in an VStack{ code }, add a Spacer() to it and add the onTap to this VStack. This will allow you to dismiss the keyboard by clicking anywhere on the screen.
See code below:
import SwiftUI
struct ContentView: View {
#State private var text: String = "Test"
var body: some View {
VStack {
HStack {
TextField("Hello World", text: $text)
Spacer()
}
Spacer()
}
.background(Color.red)
.onTapGesture {
self.endEditing()
}
}
func endEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
Changing the background color of an HStack or VStack to red simplifies figuring out where the user may click to dismiss.
Copy and paste code for a ready to run example.