Skip to content

Gestures 🎉

Choose a tag to compare

@MihaelIsaev MihaelIsaev released this 17 Apr 21:38
· 134 commits to master since this release

Tested, Fixed and Improved all the gestures

We support all available gestures

TapGestureRecognizer

TapGestureRecognizer(taps: 1, touches: 1)

or

TapGestureRecognizer()
    .numberOfTapsRequired(1)
    .numberOfTouchesRequired(1)

💡numberOfTapsRequired and numberOfTouchesRequired also accept @State

also you can conveniently call onTapGesture at any view

.onTapGesture {}
.onTapGesture { view in }
.onTapGesture { view, state in }
.onTapGesture { view, state, recognizer in }
.onTapGesture(taps: 1, touches: 1) { view, state in }
.onTapGesture(taps: 1, touches: 1) { view, state, recognizer in }
.onTapGesture(taps: 1, touches: 1, $someState)
.onTapGesture(taps: 1, touches: 1, on: .ended) { }
.onTapGesture(taps: 1, touches: 1, on: .ended) { view in }

LongPressGestureRecognizer

LongPressGestureRecognizer(taps: 0, touches: 1, minDuration: nil, allowableMovement: nil)

or

LongPressGestureRecognizer(taps: 0, touches: 1)
    .minimumPressDuration(500)
    .allowableMovement(10)

💡minimumPressDuration and allowableMovement also accept @State

also you can conveniently call onLongPressGesture at any view

.onLongPressGesture { view in }
.onLongPressGesture { view, state in }
.onLongPressGesture { view, state, recognizer in }
.onLongPressGesture(taps: 1, touches: 1) { view, state in }
.onLongPressGesture(taps: 1, touches: 1) { view, state, recognizer in }
.onLongPressGesture(taps: 1, touches: 1, $someState)
.onLongPressGesture(taps: 1, touches: 1, on: .ended) { }
.onLongPressGesture(taps: 1, touches: 1, on: .ended) { view in }

PinchGestureRecognizer

PinchGestureRecognizer(scale: 10)

or

PinchGestureRecognizer().scale(10)

💡scale also accept @State

also you can conveniently call onPinchGesture at any view

// there are a lot of convenient combinations of this method
.onPinchGesture { view, state, recognizer in
    print("changed scale: \(recognizer.scale) velocity: \(recognizer.velocity)")
    view.size(200 * r.scale)
}

RotationGestureRecognizer

RotationGestureRecognizer(rotation: 2)

or

RotationGestureRecognizer().rotation(2)

💡rotation also accept @State

also you can conveniently call onRotationGesture at any view

// there are a lot of convenient combinations of this method
.onRotationGesture { view, state, recognizer in
    if state == .changed {
        view.transform = CGAffineTransform(rotationAngle: recognizer.rotation)
    }
}

SwipeGestureRecognizer

SwipeGestureRecognizer(direction: .left, touches: nil)

or

SwipeGestureRecognizer(direction: .left)
    .numberOfTouchesRequired(1)

💡numberOfTouchesRequired also accept @State

also you can conveniently call onSwipeGesture at any view

// there are a lot of convenient combinations of this method
.onSwipeGesture(direction: .left) { view, state, recognizer in }

PanGestureRecognizer

PanGestureRecognizer(minTouches: 1, maxTouches: 2)

or

PanGestureRecognizer()
    .minimumNumberOfTouches(1)
    .maximumNumberOfTouches(1)

💡minimumNumberOfTouches and maximumNumberOfTouches also accept @State

also you can conveniently call onPanGesture at any view

// there are a lot of convenient combinations of this method
.onPanGesture { view, state, recognizer in }

ScreenEdgePanGestureRecognizer

ScreenEdgePanGestureRecognizer(edges: .all)

and additional .edges method gives you an ability to change edges property later

.edges(.left)

💡edges also accept @State

also you can conveniently call onScreenEdgePanGesture at any view

// there are a lot of convenient combinations of this method
.onScreenEdgePanGesture(edges: .left) { view, state, recognizer in }

HoverGestureRecognizer

HoverGestureRecognizer()

you can conveniently call onHoverGesture or hovered at any view

.hovered {
    print("hovered: \($0)")
}

or

.onHoverGesture { view, state, recognizer in
        switch state {
        case .began: 
            print("began")
            view.backgroundColor = .magenta
        case .changed: 
            print("changed") 
            view.backgroundColor = .orange
        case .ended: 
            print("ended") 
            view.backgroundColor = .green
        default: print("default")
        }
}

State tracking

Any gesture recognizer has tracking methods

There are universal trackState method which contains state and optionally recognizer

.trackState { state, recognizer in
    // do switch/case here
}

💡trackState can accept @State

And additionally you have an ability to listen for exact state easily 👍

.onPossible { recognizer in }
.onBegan { recognizer in }
.onChanged { recognizer in }
.onEnded { recognizer in }
.onCancelled { recognizer in }
.onFailed { recognizer in }

💡recognizer is optional

Delegate

Any gesture recognizer has its delegate methods available directly

You can set delegate simply like this

.delegate(...)

Additionally you can use these convenient methods below and even combine them with the classic delegate

.shouldBegin { recognizer in
    return true
}
.shouldReceivePress { recognizer, press in
    return true
}
.shouldReceiveTouch { recognizer, touch in
    return true
}
.shouldRequireFailureOfOtherGestureRecognizer { currentRecognizer, otherRecognizer in
    return false
}
.shouldBeRequiredToFailByOtherGestureRecognizer { currentRecognizer, otherRecognizer in
    return false
}
.shouldRecognizeSimultaneouslyWithOtherGestureRecognizer { currentRecognizer, otherRecognizer in
    return true
}

How to add a gesture to view

UView().gesture(myGesture)

or

UView().gestures(myGesture1, myGesture2)

or even

UView().gestures {
    myGesture1
    myGesture2
    // unlimited amount
}

Multiple gestures at the same time (simple example for pinch + rotate)

UView().size(200).background(.red).centerInSuperview().gestures { v in
    PinchGestureRecognizer().shouldRecognizeSimultaneouslyWithOtherGestureRecognizer { og in
        print("PinchGestureRecognizer shouldRecognizeSimultaneouslyWith: \(og.tag)")
        return true
    }.trackState { s, r in
        if s == .changed {
            v.size(200 * r.scale)
        }
    }.tag(3)
    RotationGestureRecognizer().shouldRecognizeSimultaneouslyWithOtherGestureRecognizer { og in
        print("PinchGestureRecognizer shouldRecognizeSimultaneouslyWith: \(og.tag)")
        return true
    }.trackState { s, r in
        if s == .changed {
            v.transform = CGAffineTransform(rotationAngle: r.rotation)
        }
    }.tag(4)
}

View's touch methods which available without gesture recognizers

.touchesBegan { view, touch, event in }
.touchesMoved { view, touch, event in }
.touchesEnded { view, touch, event in }
.touchesCancelled { view, touch, event in }

💡 All the methods above has its convenient shorter variations