SwiftUI Segmented Picker element is grey and disabled - ios

I've added a Picker (SegmentedPickerStyle) to my project using SwiftUI as shown:
Picker(selection: $selectedType, label: Text("Type")) {
Text("Translation")
Text("Highlights")
}
.pickerStyle(SegmentedPickerStyle())
But for some reason, the result (both in canvas and the simulator) is a grey, disabled picker (please see screenshot attached).
What I try to achieve:
Does anyone has an idea what am I doing wrong?

Try as following
#State private var selectedType = 0
...
Picker(selection: $selectedType, label: Text("Type")) {
Text("Translation").tag(0)
Text("Highlights").tag(1)
}
.pickerStyle(SegmentedPickerStyle())

Your picker has 2 Text items, "Translation" & "Highlights". So your selection will be either of those Strings.
Create a #State variable to track when that selection changes and to show the new 'State'.
#State private var selectedType = "Translation"
...
Picker(selection: $selectedType, label: Text("Type")) {
Text("Translation")
Text("Highlights")
}
.pickerStyle(SegmentedPickerStyle())

Related

Why there is a padding beneath a text in swiftUI when i have applied none? is this a bug or a feature?

I have a simple layout, a VStack that has two children a Text and another HStack. and very weirdly SwiftUI applied a large padding beneath the text. and more weirdly the way to solve it is to add a padding but i have to set it to 0.1. this will solve the problem and it will be drawn correclty. I want to know is this just a mere bug or there is something i don't know about swiftUI and Stacks? here is the code and also the screenshots:
struct SettingScreen: View {
let navigationHeight : CGFloat
#Environment(\.locale) var locale : Locale
var isKurdish : Bool {
locale.identifier == "ku"
}
var body: some View {
VStack{
Text("Language")
.localeFont(font: .myTitle)
HStack{
RecheckSelectableButtonCard(
imageName: "flag_uk",
text: "English",
isActive: !isKurdish,
onCardClick: {}
)
.environment(\.locale, .init(identifier: "en-US"))
.padding(.trailing,16)
RecheckSelectableButtonCard(
imageName: "flag_kurdistan",
text: "کوردی",
isActive: isKurdish,
onCardClick: {}
)
.environment(\.locale, .init(identifier: "ku"))
}
.padding([.leading,.trailing],16)
Spacer()
}
.padding(.bottom,navigationHeight)
}
}
These cards are my custom cards and I'm 100% sure that the HStack and the cards are not the problem.
Here is the before adding padding to the text
And this is the after
it also had the same behavior when i run it on my phone
struct SettingScreen: View {
let navigationHeight : CGFloat
#Environment(\.locale) var locale : Locale
var isKurdish : Bool {
locale.identifier == "ku"
}
var body: some View {
VStack{
Text("Language")
.localeFont(font: .myTitle)
.padding(.bottom,0.1) // This solves the problem
HStack{
RecheckSelectableButtonCard(
imageName: "flag_uk",
text: "English",
isActive: !isKurdish,
onCardClick: {}
)
.environment(\.locale, .init(identifier: "en-US"))
.padding(.trailing,16)
RecheckSelectableButtonCard(
imageName: "flag_kurdistan",
text: "کوردی",
isActive: isKurdish,
onCardClick: {}
)
.environment(\.locale, .init(identifier: "ku"))
}
.padding([.leading,.trailing],16)
Spacer()
}
.padding(.bottom,navigationHeight)
}
}```
Can anyone explain to me is there another way to solve this issue ?
VStack applies its own spacing between items. There is no documentation on how it chooses its spacing, but it's trying to make it "good" on each platform. What it chooses can depend on the exact views, and likely adding your own .padding changes its mind about what it should do.
You can control the spacing when you create the VStack. I often find that I either want the default or zero:
VStack(spacing: 0) { ... }
With zero spacing from the VStack, you can manage it by hand with padding or fixed-sized Spacers if things get too close.

SwiftUI: strange offset on tap when reopening app with a `sheet` open

I am facing out a strange behavior that really looks like a SwiftUI bug.
When I leave the app with a .sheet open and reopen it, all content from parent has an offset on tap. It is difficult to explain (and English is not my mother tongue) so here is a really simple example:
struct ContentView: View {
#State private var isOpen = false
var body: some View {
Button(action: {
isOpen.toggle()
}, label: {
Text("Open sheet")
.foregroundColor(.white)
.padding()
.background(.blue)
})
.sheet(isPresented: $isOpen, content: {
Text("Sheet content")
})
}
}
To reproduce the issue follow those steps:
Tap just below to the top border of blue button Open sheet: the sheet opens as expected.
When the sheet is open, close the app (go back to Springboard, cmd+shift+H on iOS Simulator).
Reopen the app. You're still on the sheet view.
Close the sheet. You're back on main view with blue button. Here is the bug:
Tap again on the top of blue button, right below the top border. Nothing happens. You have to click few pixels below. There is an offset that makes all tappable items on main view not aligned.
Does anyone have seen this bug also? Is there something I do wrong?
Other notices:
When closing the app from main view, the bug doesn't appear. And even when the bug is here and I close the app from main view and reopen, the bug disappears.
If I use a .fullScreenCover instead of .sheet, the bug doesn't appear.
It really looks like a bug with .sheets open.
EDIT:
I have tried two workarounds but both don't work:
Embed the Button in an external View.
Replace Button with only the Text and add .onTapGesture{ ... } modifier to toggle isOpen #State property.
EDIT 2:
After hours of tries I could find something interesting: if, in the sheet content, I add a button to dismiss the sheet, the bug doesn't appear anymore. But if I dismiss the sheet with finger (drag from top to bottom), it still appears.
Here is modified code:
struct ContentView: View {
#State private var isOpen = false
var body: some View {
Button(action: {
isOpen.toggle()
}, label: {
Text("Open sheet")
.foregroundColor(.white)
.padding()
.background(.blue)
})
.sheet(isPresented: $isOpen, content: {
SheetContent()
})
}
}
struct SheetContent: View {
#Environment(\.dismiss) var dismiss
var body: some View {
Button(action: { dismiss() }, label: {
Text("Dismiss sheet")
})
}
}
It looks like there is something with calling (or not) the #Environment(\.dismiss) var dismiss.
The current state is a bit better as few days ago as the bug only appears when user dismiss the sheet by dragging down. But there is still something wrong.
Is there a way to programmatically call dismiss() when sheet is closed by dragging down?

SwiftUI NavigationSplitView on iPad: remove accent from selected item in Sidebar

I am adopting NavigationSplitView for an app to be used on an iPad as well as on an iPhone.
In my code below, I want to highlight the the selected item in the Sidebar only with the word "Selected".
When running for iPad Air 5th generation, the Sidebar appears differently between the preview and the simulator:
In the preview, the behaviour is exactly what I want: the word "Selected" indicates the item visible in the detail view (see picture below without blue border).
However, when running on the simulator, an accent rectangle is visible around the selection (see picture below with blue border). My goal is to remove this rectangle.
In fact, if we remove the .listRowBackground() modifier, in the preview the accent is light gray, in the simulator is blue.
Some things I tried:
Replacing .listRowBackground(EmptyView()) with .listRowBackground(Collar.clear): no success.
Using .accentColor(.clear): it does not work (the rectangle gets white), and moreover it is being deprecated, so I want to avoid it.
Adding .tint(.clear) and listItemTint(.clear): no success.
Replacing List with ForEach, but then I have to re-create the layout of the rows, and the result is not the same.
I need to keep the "yellow" background.
Does anyone know how to remove that rectangle?
My code:
struct MyView: View {
#State private var selected: MyContent?
let list = [MyContent("First"), MyContent("Second"), MyContent("Third")]
var body: some View {
NavigationSplitView {
List(list, selection: $selected) { item in
NavigationLink(value: item) {
HStack {
Text(item.title)
Spacer()
Text(selected == item ? "Selected" : "")
}
.foregroundColor(.primary)
}
.listRowBackground(EmptyView())
}
.scrollContentBackground(.hidden)
.listStyle(.plain)
.background(.yellow)
} detail: {
if let selected {
Text("Detail of \(selected.title)")
}
}
}
}
struct MyContent: Identifiable, Hashable {
let id = UUID()
let title: String
init(_ title: String) {
self.title = title
}
}
What I want to achieve (OK in the preview):
The rectangle I want to remove (running on the simulator):
Deploying for iOS 16.0 on Xcode 14.

SwiftUI - Button action draws on an image

Hobbyist ios coder here...
I have an old Objective C project I am trying to recreate in swiftui.
When I click a button, it draws a CGRect and fills in the peramiters of image source from the IBAction I wrote out that i can then drag arround the screen.
Old way I used to do it
How do i do this in SwiftUI?
My empty SwiftUI Button Code
I currently have an image drawn within a VStack that I can move arround and resize, but I want it to not exist on app load, but for it and others to be drawn on user request. IE button press.
I have no idea what it is im supposed to search for to find this answer as searching for button and image instantly gives me tutorials on how to add images to a button, not a button that draws a fresh interactable element on the view.
Thank you to anyone who can shed more light on this.
EDIT - On pressing the button a second time I need the image to spawn again so there would be multiple instances of it.
I'm not 100% sure if I understand this correctly, but it's simply a matter of displaying an image when a button is clicked?
You already said that you got an image with the desired behavior, but you don't want it to be there from the beginning. I think you are looking for an alternative in SwiftUI for addSubview, but there is no direct one.
What you might be looking for is #State in SwiftUI. Changing a #State variable will force your view to redraw itself. (There are more then just #State variables that to this)
You can draw your Image based on a condition. On your button click you could change the state variable that your condition is based on to redraw your view and to display your Image. I use the toggle() function in my example, so clicking the Button a second time will result in removing the image.
import SwiftUI
struct ContentView: View {
#State private var showImage = false
var body: some View {
VStack {
if showImage {
Image(systemName: "gear") // Your working image
}
Button(action: {
self.showImage.toggle()
}, label: {
Text("draw image")
})
}
}
}
Here is an example how you could add more and more Images when clicking the button again and again. I changed the Type of the #State variable to an array and then iterate over that array via a ForEach.
import SwiftUI
struct ContentView: View {
#State private var images: [UUID] = []
var body: some View {
VStack {
ForEach(images, id: \.self) { _ in
Image(systemName: "gear") // Your working image
}
Button(action: {
self.images.append(UUID())
}, label: {
Text("draw image")
})
}
}
}

Modifiers of elements inside segmented picker don't work

I have a code:
#Binding var hand: Hand
var body: some View {
HStack {
Text("Hand: ")
Picker(selection: $hand, label: Text("Strength")) {
Text("JIUJIU").tag(0).foregroundColor(.blue)
Text("BLABLA").tag(1).rotationEffect(Angle(degrees: 35))
}.pickerStyle(SegmentedPickerStyle())
}
}
There is foregroundColor(.blue) and rotationEffect(Angle(degrees: 35)) modifiers inside elements of Picker. But in fact I see nor any effect:
Why modifiers don't work?
It is your pickerStyle(). The documentation says concerning the SegmentedPickerStyle:
Note: Only supports segments of type Label and Image. Passing any
other type of view will result in a visible, but empty, segment.
I think that is why you only see the text. I have tried using another style and that worked fine.

Resources