Is there a possibility to deactivate a button in SwiftUI? - swiftui

Is there a possibility to deactivate a button in SwiftUI? Can not find anything?
I want to do a download with Alamofire and then activate the button after successful download.

You can use the .disabled modifier. According to the documentation:
Adds a condition that controls whether users can interact with this
view.
import SwiftUI
struct ContentView: View {
#State private var buttonDisabled = true
var body: some View {
Button(action: {
//your action here
}) {
Text("CLICK ME!")
}
.disabled(buttonDisabled)
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
You can set your buttonDisabled State var to false when your download completes.

Related

Make List items selectable in edit mode, EditMode example from documentation not working

I want to add the possibility to select items in a list when edit mode is selected, additionally to the delete and move option. Ideally I want to use the existing edit, delete and move buttons instead of writing my own. I tried the example from the documentation. It's not working for me. The value of editMode is always .inactive. I'm using XCode 14. The deployment target of my app is iOS 16.0.
This is my source code:
import SwiftUI
struct ContentView: View {
#Environment(\.editMode)
private var editMode
#State
private var name = "Maria Ruiz"
var body: some View {
NavigationView {
Form {
if editMode?.wrappedValue.isEditing == true {
TextField("Name", text: $name)
} else {
Text("test")
}
}
.animation(nil, value: editMode?.wrappedValue)
.toolbar { // Assumes embedding this view in a NavigationView.
EditButton()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
It always shows the test text. I also tried a variant with the .onChange modifier, with the same result.
Forwarding the fix from https://developer.apple.com/forums/thread/716434:
Try extracting the parts that access the editMode property from the
container that changes based on it, like List/Form.
struct ContentView: View {
var body: some View {
NavigationView {
Form {
MyForm()
}
.toolbar { // Assumes embedding this view in a NavigationView.
EditButton()
}
}
}
}
and
struct MyForm: View {
#Environment(\.editMode)
private var editMode
#State
private var name = "Maria Ruiz"
var body: some View {
Text(String(editMode!.wrappedValue.isEditing))
if editMode?.wrappedValue.isEditing == true {
TextField("Name", text: $name)
} else {
Text("test")
}
}
}

How to hide/remove WatchOS 9's .sheet cancel button?

Previous to watchOS 9 you could present a sheet without any out of the box way to cancel or dismiss. However starting in watchOS 9 presenting a sheet also presents a cancel button in the top left of the navigation bar. How can I remove this and handle dismissing myself?
import SwiftUI
struct ContentView: View {
#State var isShowingSheet = false
var body: some View {
VStack {
Button("show sheet") {
isShowingSheet.toggle()
}
}
.sheet(isPresented: $isShowingSheet) {
Text("Sheet 1")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Same issue here, tried an empty view in a ToolBarItem but did not work.
I ended up using this:
NavigationView {
// Your stuff here
}
.navigationTitle("")
.navigationBarTitleDisplayMode(.inline)
What you do is that you set an empty title, and you tell it to go at the same place as of the cancel button.
PS:it looks like #Kurt Lane was a bit faster in the comment. Credits to him.

Sheet is Only Presented Once in SwiftUI

I have an app which presents a sheet. It works for the first time but when I click on it again it does not work. I am making isPresented false when you dismiss a sheet but when I tap on the Filter button again, it does not show the sheet.
ContentView
struct ContentView: View {
#State private var isPresented: Bool = false
var body: some View {
NavigationView {
List(1...20, id: \.self) { index in
Text("\(index)")
}.listStyle(.plain)
.navigationTitle("Hotels")
.toolbar {
Button("Filters") {
isPresented = true
}
}
.sheet(isPresented: $isPresented) {
isPresented = false
} content: {
FilterView()
}
}
}
}
FilterView:
import SwiftUI
struct FilterView: View {
#Environment(\.presentationMode) private var presentationMode
var body: some View {
ZStack {
Text("FilterView")
Button {
// action
presentationMode.wrappedValue.dismiss()
} label: {
Text("Dismiss")
}
}
}
}
struct FilterView_Previews: PreviewProvider {
static var previews: some View {
FilterView()
}
}
A couple of things to note from my experience.
Firstly, when using the isPresented binding to show a sheet, you don't need to reset the bound value in a custom onDismiss handler to reset it to false - that's handled for you internally by SwiftUI as part of the dismiss action.
So your modifier can be simplified a little:
.sheet(isPresented: $isPresented) {
FilterView()
}
Secondly, when running an app in the Simulator I've noticed that when you come back to the main view after dismissing a sheet you have to interact with the app somehow before clicking on the toolbar button, or the action won't trigger.
In cases like this, just scrolling the list up or down a little would be enough, and then the toolbar button works as you'd expect.
I've not encountered the same thing while running apps on a physical device – whether that's because the bug isn't present, or just that it's a lot easier to interact with the app in some microscopic form of gesture, I couldn't say.

Enable the button if there is input in the TextField SwiftUI

For the first time to question. I'm sorry if I'm rude.
I want to create a mechanism that prevents the button from being pressed when there is no input in the TextField. On the contrary, I want to enable the button if there is input.
I wrote it like this, but I get an error saying "Cannot find'$ task' in scope".
Do you know why?
import SwiftUI
import CoreData
struct TFenableView: View {
#ObservedObject var task: Task
#Environment(\.managedObjectContext) var viewContext
#Environment(\.presentationMode) var presentation
var taskNameIsValid: Bool {
return !task.name.isEmpty
}
var body: some View {
Form {
TextField("Edit TaskName", text: $task.name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Button(action: {
Task.save(in: self.viewContext)
self.presentation.wrappedValue.dismiss()
}) {
Text("Update!")
}.padding()
.disabled(!taskNameIsValid)
}
.navigationBarTitle("Editing screen")
.navigationBarBackButtonHidden(!taskNameIsValid)
}
}
struct TFenableVieew_Previews: PreviewProvider {
static var previews: some View {
TFenableView()
}
}
TextField photo

How to fire `onAppear` method when a view comes back from `App Settings` changing a notifications setting?

I'm currently developing an application using SwiftUI.
I'm trying to make an app using Local Notification.
I want to reflect on a set of Allow Notifications in an App Settings to some views.
But when a view comes back from the App Settings using a navigation link I attached(not back button), the onAppear method doesn't fire and I can't show a collect value...
In my codes:
1.Tap Open Settings to navigate to an App Setting
2.Change a Notifications setting
3.Tap NotificationTest button
4.Come back to ContentView then onAppear method doesn't fire
How could I solve this problem?
Here are the codes:
ContentView.swift
import SwiftUI
struct ContentView: View {
#State var isNotification = false
var body: some View {
VStack{
Text(isNotification ? "STATUS:ON" : "STATUS:OFF")
.padding()
Text("Open Settings")
.padding()
.onTapGesture {
UIApplication.shared.open(URL(string:UIApplication.openSettingsURLString)!)
}
}
.onAppear(){
confirmNotification()
}
}
func confirmNotification(){
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .badge, .sound]){
success, error in
if success{
isNotification = true
print("Notification set")
}else{
isNotification = false
}
}
}
}
NotificationTestApp.swift
import SwiftUI
#main
struct NotificationTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Xcode: Version 12.0.1
iOS: 14.0
Life Cycle: SwiftUI App
View has already appeared, just application is in background. Try to use instead (or additionally) scenePhase
struct ContentView: View {
#Environment(\.scenePhase) private var scenePhase
#State var isNotification = false
var body: some View {
VStack{
Text(isNotification ? "STATUS:ON" : "STATUS:OFF")
.padding()
Text("Open Settings")
.padding()
.onTapGesture {
UIApplication.shared.open(URL(string:UIApplication.openSettingsURLString)!)
}
}
.onAppear(){
confirmNotification()
}
.onChange(of: scenePhase) { phase in
switch phase {
case .active:
confirmNotification()
default:
break
}
}
}