SwiftUI List NavigationView onDelete alert confirmation has ugly animation - ios

The problem is that whenever you put the list in navigationView, the animation of the delete cancelation of the list row is not so nice. Am I doing something wrong in my body property?
var body: some View {
NavigationView {
VStack {
List {
ForEach(self.contacts){ contact in
ContactRow(contact: contact)
}.onDelete { self.setDeletIndex(at: $0) }
}
.alert(isPresented: $showConfirm) {
Alert(title: Text("Delete"), message: Text("Sure?"),
primaryButton: .cancel(),
secondaryButton: .destructive(Text("Delete")) {
self.delete()
})
}
.listStyle(PlainListStyle())
.navigationTitle("Contacts")
.navigationBarItems(trailing: HStack {
Button("Add", action: self.addItem)
})
}
}
}

Related

Minimize or bring back sheet in SwiftUI

I have a Voip calling app using CallKit and when call received, it will open a view call IncomingView in a sheet in my SwiftUI app. So far so good. But i want to minimize the sheet and can navigate to other pages and preferably shows a green bar at the navigation (similar to WhatApp) that indicates the call is going on and when i tap there, it should bring back my "IncomingView".
here is my code:
struct MainView: View {
let acceptPublishser = NotificationCenter.default
.publisher(for: Notification.Name.DidCallAccepted)
let endPublisher = NotificationCenter.default
.publisher(for: Notification.Name.DidCallEnd)
var body: some View {
NavigationView {
TabView {
TabListView()
.tabItem {
Label("Home", systemImage: "house.fill")
}
ContactListView()
.tabItem {
Label("Contacts", systemImage: "person.crop.circle")
}
ProfileView()
.tabItem {
Label("Profile", systemImage: "person.crop.circle")
}
}
.padding(0)
.onAppear(){
self.showModal = MyCallDelegate.shared.isIncomingCall
}
.sheet(isPresented: $showModal){
IncomingCallView() // -> Present IncomingCallview() as sheet
}
.accentColor(Color(.green))
}.onReceive(self.acceptPublishser, perform: { output in
showModal = true
})
.onReceive(self.endPublisher, perform: { output in
showModal = false
})
}
}
struct IncomingCallView: View {
var body: some View {
VStack{
Spacer()
Text("callerId").foregroundColor(.white)
Text("Timer").foregroundColor(.white)
}
}

SwiftUI Button action statements

I'd like to do a statement in button block, if textfield is empty, then get an alert and you can't acces the other ViewController, if you fill he textfield, then you can start play:
LaunchView.swift :
Button(action: {
if username.isEmpty {
showingAlert = true
} else {
//Here I would like to acces another view
}
}) {
Text("PLAY")
.padding()
.foregroundColor(.black)
.frame(width: 350)
.background(Color.white)
.clipShape(Capsule())
.shadow(radius: 15)
}.alert(isPresented:$showingAlert) {
Alert(
title: Text("Error"),
message: Text("Enter your username"),
dismissButton: .cancel()
)
}
And I have one more question, how could I use a variable from LaunchView, in FirstView?
Like, I would like to get the name from LaunchView's textfield, in alerts in FirstView:
"(username), your score is X"
FirstView.swift:
.alert(isPresented: $showingScore) {
Alert(title: Text(scoreTitle), message: Text("Your score is \(point)"), dismissButton: .default(Text("Continue")) {
self.askQuestion()
})
}

SwiftUI NavigationLink: how to call a function before showing destination view

I would like to call a function, after clicking on an item, and before displaying the destination view.
The code below doesn't seem to work: myFunction is called, but the destination view is not shown.
It looks like the onTapGesture overwrites the NavigationLink destination.
NavigationView {
List(restaurants) { restaurant in
NavigationLink(destination: RestaurantView(restaurant: restaurant)) {
RestaurantRow(restaurant: restaurant)
}.onTapGesture { myModel.myFunction(restaurant) }
}
}
How can I have both, when clicking on a list item?
function is called
destination view is shown
Try to add NavigationLink into a Button, like:
Button(action: {
//Call here
myModel.myFunction(restaurant)
}, label: {
NavigationLink(destination: RestaurantView(restaurant: restaurant)) {
RestaurantRow(restaurant: restaurant)
}
})
EDIT pasted test code, try directly
struct TestNavigationView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Detail").onAppear() {
test()
}) {
Text("Click")
}
}
}
}
func test() {
print("Hell0")
}
}
another approach: (might not work if List there)
struct TestNavigationView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: Text("Detail")) {
Text("Click")
}.simultaneousGesture(TapGesture().onEnded{
test()
})
}
}
}
func test() {
print("Hell0")
}
}

NavigationLink in contextMenu

I've been experimenting with NavigationLink in a contextMenu, and have run into this issue:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("foo")
.contextMenu {
NavigationLink(destination: Text("foo context destination")) { //works
Text("foo context")
}
}
.padding(.all)
NavigationLink(destination: Text("bar destination")) { //works
Text("bar")
.contextMenu {
NavigationLink(destination: Text("bar context destination")) { //does not work
Text("bar context")
}
}
}
.padding(.all)
} //VStack
} //NavigationView
} //body
} //ContentView
As shown in the code, NavigationLink within a contextMenu seems to work for 'foo context' but not for 'bar context'. The difference is that 'foo' is wrapped in a NavigationLink, but 'bar' is not. I would appreciate any suggestions for solving the issue with 'bar context' navigation.
Edit: To clarify, I would like to find a way to navigate to "bar destination" by tapping "bar", OR navigate to "bar context destination" by tapping "bar context" in the contextMenu. The problem seems to be that when "bar" is wrapped in NavigationLink, then NavigationLink in the contextMenu attached to "bar" is not working.
Thanks!
I have made changes to your code so that both "foo" and "bar" works.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Text("foo")
.contextMenu {
NavigationLink(destination: Text("foo context destination")) { //works
Text("foo context")
}
}
.padding(.all)
Text("bar")
.contextMenu {
NavigationLink(destination: Text("bar context destination")) { //does not work
Text("bar context")
}
}
.padding(.all)
} //VStack
} //NavigationView
} //body
} //ContentView

SwiftUI: How to execute closure when Alert is dismissed?

I've been trying out swiftUI and looked at this Ray Wenderlich tutorial... I noticed they didn't re-implement the "nextRound" functionality... so I tried to do it myself. Ran into a problem (which maybe they did, also):
The basic question is more general:
Using swiftUI, how do you trigger a function when an Alert is dismissed -- when the user clicks "OK." ?
I've tried using the dismissButton argument of the Alert constructor...
(and also the .onDisappear method of View but I can't figure out how to apply it to the Alert view.)
Code:
import SwiftUI
struct ContentView: View {
#State var shouldShowAlert: Bool = false
// this never gets called
func onAlertDismissed() {
print("you will not see this in the console")
}
// this doesn't seem to work
var dismissButton: some View {
Button(action: {
self.onAlertDismissed()
}) {
// Bilbo Baggins does not appear -- "OK" still shows
Text("BILBO BAGGINS")
}
}
var body: some View {
VStack {
Spacer()
Button(action: {
self.shouldShowAlert = true
}) {
Text("show the alert!")
}
Spacer()
}.alert(isPresented: $shouldShowAlert, content: {
// what to add here?
Alert(title: Text("Alert:"), message: Text("press OK to execute onAlertDismissed()..."))
// what I have tried and doesn't work:
/*
Alert(title: Text("Alert:"), message: Text("press OK to execute onAlertDismissed()..."), dismissButton: self.dismissButton as? Alert.Button)
*/
})
}
}
The button is constructed a little differently. You basically have to use a static factory method from Alert.Button to construct them and pass those in.
Alert(title: Text("Alert:"),
message: Text("press OK to execute default action..."),
dismissButton: Alert.Button.default(
Text("Press ok here"), action: { print("Hello world!") }
)
)
Alert(title: Text("Alert!"), message: Text("Message"),
primaryButton: Alert.Button.default(Text("Yes"), action: {
print("Yes")
}),
secondaryButton: Alert.Button.cancel(Text("No"), action: {
print("No")
})
)
It's possible to create alerts like this:
import SwiftUI
struct ContentView: View {
#State var showingAlert = false
var body: some View {
VStack {
HStack {
Button(action: {
self.showingAlert = true
})
{
Text("Save")
.font(.headline)
}
.alert(isPresented: $showingAlert, content: {
return Alert(
title: Text("Save Product"),
message: Text("Are you sure you want to save the changes made?"),
primaryButton: .default(Text("Yes"), action: {
//insert an action here
}),
secondaryButton: .destructive(Text("No")))
})
}
}
}
}
By looking at your code, it appears you don’t include a button in the alert propert, so your alert is not executing any action, in swiftui the alert signature is
init(title: Text, message: Text? = nil, primaryButton: Alert.Button, secondaryButton: Alert.Button)
Implement the signature properly is the first step

Resources