Target is a modification with the following behavior:
(but only with 2 buttons - 1 on the left side, 1 on the right)
Behavior:
short swipe shows the buttons and gives the user the ability to click it.
strong long swipe presses button.
ability to use 2 finger gesture
Minimal reproducible example:
import SwiftUI
public extension View {
func SwiperizeItem(closureL: @escaping () -> (), closureR: @escaping () -> ()) -> some View
{
self.modifier( SwiperizeItemModifier(closureL: closureL, closureR: closureR) )
}
}
struct SwiperizeItemModifier: ViewModifier {
@State var dragOffset = CGSize.zero
@State var offset1Shown = CGSize(width: 100, height: 0)
@State var offset1Click = CGSize(width: 250, height: 0)
@State var offset2Shown = CGSize(width: -100, height: 0)
@State var offset2Click = CGSize(width: -250, height: 0)
@State var BackL = Color.green
@State var BackR = Color.red
@State var ForeColorL = Color.white
@State var ForeColorR = Color.white
@State var closureL: () -> Void
@State var closureR: () -> Void
func body(content: Content) -> some View {
HStack{
Button(action: { closureL() } ) {
Text("Left")
.foregroundColor(ForeColorL)
}
.background(BackL)
.frame(maxWidth: dragOffset.width > 0 ? dragOffset.width : 0)
.fixedSize()
content
//.padding([.leading, .trailing], 20)
.animation(.spring())
.offset(x: self.dragOffset.width)
.gesture(DragGesture()
.onChanged(){
value in
self.dragOffset = value.translation
}
.onEnded(){
value in
if ( dragOffset.width > 0 ) {
if ( dragOffset.width < offset1Shown.width) {
self.dragOffset = .zero
}
else if ( dragOffset.width > offset1Shown.width && dragOffset.width < offset1Click.width ) {
self.dragOffset = offset1Shown
}
else if ( dragOffset.width > offset1Click.width ) {
self.dragOffset = .zero
closureR()
}
}
else {
if ( dragOffset.width > offset2Shown.width) {
self.dragOffset = .zero
}
else if ( dragOffset.width < offset2Shown.width && dragOffset.width > offset2Click.width ) {
self.dragOffset = offset2Shown
}
else if ( dragOffset.width < offset2Click.width ) {
self.dragOffset = .zero
closureL()
}
}
}
)
}
}
}
// ____________________
struct GuestureItem_Previews: PreviewProvider {
static var previews: some View {
Group {
Text("Hello")
.padding(.all, 30)
.background( Color( NSColor.red ) )
.SwiperizeItem(closureL: { print("click left") }, closureR: { print("click right") })
}
}
}
So... my problems are:
I think the solution may be related to the new release of SwiftUI components:
LazyHGrid
orOutlineGroup
. https://developer.apple.com/videos/play/wwdc2020/10031
.onDelete() is not a solution for me because it's impossible to do 2 side buttons and impossible to edit "delete" text
In iOS 15 we can finally use native Swipe Actions:
func swipeActions<T>(edge: HorizontalEdge = .trailing, allowsFullSwipe: Bool = true, content: () -> T) -> some View where T : View
They can be attached to the ForEach
container just like onMove
or onDelete
:
ForEach {
// ...
}
.swipeActions(edge: .trailing) {
Button {
print("Editing...")
} label: {
Label("Edit", systemImage: "pencil")
}
}
As long as you don't want to create custom UI for the delete button, you can take advantage of SwiftUI and use all of the built in features.
ForEach
has a modifier called .onDelete
, that gives you an IndexSet
. This represents the rows that should be deleted when the user swipes. Now if we implement the necessary logic and wrap it in an animation block, everything will work as needed.
struct ContentView: View {
@State var cars = ["Tesla Model 3", "BMW i3", "Roadster", "Cybertruck", "Agera Koenigsegg", "Rimac Concept One"]
var body: some View {
NavigationView {
List {
ForEach(cars, id: \.self) { car in
Text(car)
}
.onDelete { indexSet in
withAnimation {
cars.remove(atOffsets: indexSet)
}
}
}
.navigationTitle("My Cars")
}
}
}
Note: .onDelete
modifier is not available to use with List
, can only be applied on ForEach
.
As of now SwiftUI does not have support for creating gestures for multiple fingers. The only solution is to use UIViewRepresentable
in combination with UIPanGestureRecognizer
. Then you can set the minimumNumberOfTouches
to 2 fingers.
This post from Apple Developer Forum shows how you could achieve something similar for a simple 2 fingers tap gesture, but the idea and concept for swipe are very similar and already explained above.
Hope this helps! 😊
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With