When I add picker in form it shows me correctly to navigate on another page.But after selecting on one row it come back to previous screen and I am not able to click on it again.
I had same problem with button. It's not perfect solution, but it worked for me.
You can try add UUID as #State to your picker, and chang it when action is triggered
Like this:
#State private var pickerID = UUID()
...
Picker {...}.id(self.pickerID)
...
youAction {
.....
self.pickerID = UUID()
}
Related
The SwiftUI PhotoPicker is great for creating a button/label to press & then show a Photo Picker when the label is pressed. However, I'd like to invoke a photo picker not after the Picker's label is pressed, but after a conditional test has passed.
For example, if the user clicks on a button that would invoke a Photo Picker, I'd like to first check to see if the record the image will be attached to has been saved. If the record has been saved, I want to launch the picker. If it hasn't been saved, I'll show an alert asking if they want to save or cancel. If they select save, I'll save the record, THEN I'd like to invoke the photo picker automatically.
So can I invoke the Picker programmatically rather than have the user click it? Thanks for advice!
From iOS 16 you can do this by using the photosPicker(isPresented:
struct DemoView: View {
#ObservedObject var viewModel: DemoViewModel
var body: some View {
VStack {
Text("Demo Project")
}
.photosPicker(isPresented: $viewModel.shouldPresentPhotoPicker, selection: $viewModel.selectedPickerItem)
}
}
class DemoViewModel: ObservableObject {
#Published var shouldPresentPhotoPicker = false
#Published var selectedPickerItem: PhotosPickerItem?
func saveTheRecord() {
/// Make an async call, and wait
shouldPresentPhotoPicker = true // Shows the Picker
}
}
How can you make a TextField, that knows it's a Name-Field?
I need the Phone to suggest the User His Name when he taps my TextField.
Any ideas how to do that in SwiftUI?
Thanks for your help!
Boothosh
It sounds like you might be referring to one of the textContentType options.
For example:
struct ContentView: View {
#State private var textFieldContent = ""
var body: some View {
TextField("User name", text: $textFieldContent)
.textContentType(.givenName)
}
}
In this example, the system will suggest a given name for the field based on the contact card set to be the device's owner. On iOS, you can see a list of the UITextContentType options here. On macOS, there's a similar list here, albeit with many fewer options.
I have a VM that is implemented as follows:
LoginViewModel
class LoginViewModel: ObservableObject {
var username: String = ""
var password: String = ""
}
In my ContentView, I use the VM as shown below:
#StateObject private var loginVM = LoginViewModel()
var body: some View {
NavigationView {
Form {
TextField("User name", text: $loginVM.username)
TextField("Password", text: $loginVM.password)
Every time I type something in the TextField it shows the following message in the output window:
Binding<String> action tried to update multiple times per frame.
Binding<String> action tried to update multiple times per frame.
Binding<String> action tried to update multiple times per frame.
It is a message and not an error.
If I decorate my username and password properties with #Published then the message goes away but the body is rendered each time I type in the TextField.
Any ideas what is going on and whether I should use #Published or not. I don't think I will gain anything from putting the #Published attribute since this is a one-way binding and I don't want to display anything on the view once the username changes.
If I decorate my username and password properties with #Published then the message goes away
This is the correct solution. You need to use #Published on those properties because that is how SwiftUI gets notified when the properties change.
the body is rendered each time I type in the TextField
That is fine. Your body method is not expensive to compute.
I don't think I will gain anything from putting the #Published attribute since this is a one-way binding
You cannot be sure SwiftUI will work correctly (now or in future releases) if you don't use #Published. SwiftUI expects to be notified when the value of a Binding changes, even when a built-in SwiftUI component like TextField causes the change.
For the simple case - the state is kept in the same view or in a ModelSupport class, consists of strings or other primitive types, and there's only one of each, #Published will work fine.
I got this error with a model class containing an array of structs and using a List, and every time you type inside a TextField inside a list (or every time you select an item in a list), the view gets refreshed, and the error gets triggered.
I am thus using a DelayedTextField:
struct DelayedTextField: View {
var title: String = ""
#Binding var text: String
#State private var tempText: String = ""
var body: some View {
TextField(title, text: $tempText, onEditingChanged: { editing in
if !editing {
$text.wrappedValue = tempText
}
})
.onAppear {
tempText = text
}
}
}
and the binding update error is no more.
I’m having trouble using an arrow key as a .keyboardShortcut in SwiftUI. Sample iOS app:
struct ContentView: View {
#State var time: Date = Date()
var body: some View {
VStack {
Button("Press Me") {
time = Date()
}
.keyboardShortcut(KeyEquivalent.rightArrow, modifiers: [])
Text("\(time)")
}
}
}
This puts up a button that, when pressed, changes the time displayed in the text. I should be able to use the right arrow key on the keyboard and get it to work as well, but it doesn’t. If I change the keyboardShortcut line to, say, this:
.keyboardShortcut(KeyEquivalent(“a”), modifiers: [])
everything works as expected. You can press the “a” key and the time changes. If you hold down the command key, you get the system-provided HUD that shows the “a" shortcut. Change it to .rightAarrow and it shows the HUD but there’s an enclosed “?” for the shortcut, and the shortcut doesn’t fire when the arrow key is pressed.
(I’m aware I could do this using UIKit. Trying to understand why the SwiftUI version doesn’t work.)
I am attempting to accomplish the same objective in my MacOS SwiftUI app. Using your code as an example, I inserted the .keyboardShortcut(KeyEquivalent.rightArrow, modifiers: []) after my Button{} and it works fine. I then pasted your entire code into my ContentView and again it works fine. I do not know why it works in my MacOS app but not in your iOS app.
Copying my answer from this post. I wasn't able to use SwiftUI's commands to get this to work on iOS/iPadOS. However I found some luck using view controllers, and if you're using SwiftUI views then this will work with a hosting controller.
In your view controller, add the code below. The important bit is setting wantsPriorityOverSystemBehavior to true:
override var keyCommands: [UIKeyCommand]? {
let upArrow = UIKeyCommand(input: UIKeyCommand.inputUpArrow, modifierFlags: [], action: #selector(test))
upArrow.wantsPriorityOverSystemBehavior = true
return [upArrow]
}
#objc func test(_ sender: UIKeyCommand) {
print(">>> test was pressed")
}
(This is my first SwiftUI project; please be kind if this is a stupid question.)
I have a collection of objects which are displayed in a Picker. The picker selection is $selectedIndex, where
#State private var selectedIndex: Int = 0
I also have a
#State private var opts: OptsStruct = OptsStruct()
where elements of the OptsStruct structure are bound to SwiftUI views. The value of opts needs to change when the selectedIndex changes, because the opts property is the option shown in and selected by the Picker. (Also, I want to save the current value of selectedIndex in UserDefaults.) The problem is that I don't understand how to express these actions in SwiftUI.
I tried
#State private var selectedIndex: Int = 0 {
mutating didSet {
// save selectedIndex to UserDefaults
opts = f(selectedIndex)
}
but this causes a Segmentation Fault.
Where is the 'correct' place to put this logic. (And in general, can someone suggest some reading on how to connect changes to SwiftUI #States with general business logic.)
Thanks,
Rick
The idea of a #State variable is for it to be the single source of truth (wikipedia). This means that one variable should be the only thing that contains the "state" of your picker. In this case, I suggest using this:
$opts.selectionIndex
as the Binding for your picker. selectionIndex would then be a Int property of your OptsStruct type.