SwiftUI tap gesture blocks item deleting action in List - ios

So I have a view with List, also this view has side menu. I added tapGesture to my VStack to dismiss side menu when it's open, but then I face issue, tapGesture is blocking onDelete method of List. Any ideas how to fix that??
Here is code example:
VStack {
.....
List {
ForEach(){
//list elements here
}
.onDelete {
// delete action here
}
}
}
.onTapGesture {
// action here
}
Also, if while deleting I swipe once till the end, it's working. But if I swipe just a little and try to press Delete button nothing happens.

Replace your .onTapGesture with the simultaneousGesture modifier.
.simultaneousGesture(TapGesture().onEnded {
// action here
})

Related

SwiftUI onDrag being called twice

I'm implementing Drag & Drop using SwiftUI. The problem I'm facing is that onDrag is called twice: The first time is when long press gesture happens and the second time is after starting dragging/moving my finger (after the long press).
Also preview is displayed twice. First one on long press and the second one on actual drag. The second one looks like my view (created in makePreviewItem(...)). The first one is just a bit scaled item.
var body: some View {
ScrollView(.horizontal) {
LazyVGrid(columns: ...) {
ForEach(...) { item in
createItem(...)
.onTapGesture {
viewModel.didSelect(item)
}
.onDrag {
let haptic = UIImpactFeedbackGenerator(style: .medium)
haptic.prepare()
haptic.impactOccurred()
draggingItem = item
viewModel.didStartDragging(item)
return NSItemProvider(object: String(item.id) as NSString)
} preview: {
makePreviewItem(...)
}
.onDrop(of: [.text], delegate: DropRelocateDelegate(didFinishDragging: {
draggingItem = nil
viewModel.didFinishDragging()
}))
}
}
}
.frame(height: 100)
So I'd like to display my preview view (makePreviewItem(...)) immediately (when long press occurs) and I don't want onDrag to be called twice.
You can add a boolean. When a long press or drag is initiated then the boolean is set to true, and each gesture checks whether the boolean is true which does not run the code, once the drag or press has been completed, the boolean returns back to false. This stops the drag action being initiated twice.

iOS SwiftUI Form onTapGesture blocks child user interface functionality

the Form view seems to create troubles using the newest SwiftUI (I'm new to it and haven't tested it in older version tbh).
The simple code executes the onTapGesture function correctly when clicking on the button, although it disables all the user feedback (so not visual change in the button on pressing, hold and release) and also does not execute the button action anymore:
var body: some View
{
Form
{
Button(action: {
print("button action")
})
{
Text("Button")
}
.onTapGesture
{
print("tap button")
}
}
.onTapGesture
{
print("tap form")
}
}
When exchanging Form with HStack the visual feedback and console prints work. So it definitely seems to be an issue with the Form view.
When commenting the onTapGesture Form function the button feedback works again. So only the onTapGesture on the Form blocks all child interaction.
Does anyone know what this is - and is there a workaround?

How to resolve SwiftUI Tap Conflict?

When I use SwiftUI to make my view,I can't make the tap event work.
My Code like:
VStack{
HStack{
//SomeView...
}
.onTapGesture {
print("HStack Tap Work")
}
}
.onTapGesture {
print("VStack Tap Work")
}
And I just want to print "VStack Tap Work" when i tap the other area of VStack expect the HStack,and print "HStack Tap Work" when i tap the HStack.
But it always print "VStack Tap Work".So how can i resolve it?
The handling order might depend on real views hierarchy (because stacks usually tight around content), so try to separate gestures by priority, like
HStack {
//SomeView...
}.highPriorityGesture(TapGesture().onEnded { // high priority !!
print("HStack Tap Works")
})

Context Menu & Haptic touch in SwiftUI

I'm working on a new app using SwiftUI and I need some help in the context menu.
I want to know how I can add a custom preview for the context menu in SwiftUI?
& how I can group menu items in multiple groups & add children for any item in the menu?
also how I can make the delete button in red color? or change the colors for them?
another thing, how I can add a menu on the app icon to open a specific View or make an action like this:
In order to add a custom preview, you can use this https://developer.apple.com/documentation/swiftui/view/contextmenu(menuitems:preview:)
The preview should be something that conforms to View.
To split the items in multiple groups, just add a Divider() between the items.
In order to change the color to red for a Delete item, change the button role to .destructive as in the example below.
To add children to one item, use a Menu as below, but I don't think this approach is encouraged.
Here is an example that includes all the above.
.contextMenu {
Menu("This is a menu") {
Button {
doSomething()
} label: {
Text("Do something")
}
}
Button {
doSomethingAgain()
} label: {
Text("Something")
}
Divider()
Button(role: .destructive) {
performDelete()
} label: {
Label("Delete", systemImage: "trash")
}
} preview: {
Text("This is the preview") // you can add anything that conforms to View here
}

Make a list row selectable in SwiftUI

I'm creating a list with custom rows in SwiftUI. When I tap one of them, I want the row to turn light gray until another tap is detected.
This doesn't happen with simple non-custom lists either.
Here's my list:
List{
ForEach(blocks){ block in
BlockRow(block: block)
}
.onDelete(perform: delete)
.onMove(perform: day.move)
}
When I tap on one of the items, nothing happens. If I create a simple list with storyBoards, I get the behavior I want:
Hey so you asked this 3 months ago so I hope you got an answer somewhere or figured it out since then, but to get to the good stuff to make a button tappable I was able to get it working using this,
List {
Button (action: {
//Whatever action you want to perform
}) {
//Code to present as the cell
}
}
I would maybe try the following based on your code,
List (blocks) { block in
Button (action: {
//perform button action
}) {
//How the cell should look
BlockRow(block: block)
}
}
.onAppear()
.onDelete()

Resources