Reputation:
I need to display Sticker Label only when I try to double tab with three fingers wherever into the app. I have tried using Multi-Touch solution. Seems I can see the sticker label but I can't able to access other actions like scrollable, touchable etc,..
Here below my code,
import SwiftUI
// UIViewRepresentable for custom gesture recognition
struct GestureRecognizerView: UIViewRepresentable {
var onDoubleTap: () -> Void
func makeCoordinator() -> Coordinator {
return Coordinator(onDoubleTap: onDoubleTap)
}
class Coordinator: NSObject {
var onDoubleTap: () -> Void
var tapCount = 0
var lastTapTime: TimeInterval = 0
init(onDoubleTap: @escaping () -> Void) {
self.onDoubleTap = onDoubleTap
}
@objc func handleGesture(_ gesture: UITapGestureRecognizer) {
let currentTime = Date().timeIntervalSince1970
if currentTime - lastTapTime < 0.3 {
tapCount += 1
} else {
tapCount = 1
}
lastTapTime = currentTime
if tapCount == 2 && gesture.numberOfTouches == 3 {
onDoubleTap()
tapCount = 0
}
}
}
func makeUIView(context: Context) -> UIView {
let view = UIView()
// Add UITapGestureRecognizer to detect double-tap with three fingers
let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleGesture(_:)))
tapGesture.numberOfTapsRequired = 2
tapGesture.numberOfTouchesRequired = 3 // Three fingers
view.addGestureRecognizer(tapGesture)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
// No update required
}
}
If Use .Overlay then I can face the blocking issue. Yes I can see a transparent view. So expected Tab gesture working but remaining access doesn't work like scrollable, other touch events.
Then I tried with .background also this time I can access other actions like scrollable, other touch events but this time missing double tap with three finger detection to show sticker.
.overlay(GestureRecognizerView {
// Handle double-tap with three fingers
withAnimation {
showSticker.toggle() // Toggle sticker visibility
}
}
)
May I know having any other way to achieve "Display Sticker label only when user doing double tap with three fingers?"
If anyone provide your valuable suggestions or solutions, It will be really appreciate.
Upvotes: 0
Views: 48
Reputation:
So finally I got solution like added gestureRecognizer to UIWindow, Then I can able to achieve double tap with three fingers to display Sticker UI on everywhere into the app.
import SwiftUI
import UIKit
struct ThreeFingerTapGesture: UIViewRepresentable {
let action: () -> Void
func makeUIView(context: Context) -> UIView {
// Create a transparent UIView to attach the gesture recognizer
let view = UIView()
view.backgroundColor = .clear
// Add gesture recognizer directly to the window
DispatchQueue.main.async {
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first {
let gesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleGesture(_:)))
gesture.numberOfTouchesRequired = 3
gesture.numberOfTapsRequired = 2
gesture.delegate = context.coordinator
gesture.cancelsTouchesInView = false
window.addGestureRecognizer(gesture)
}
}
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator(action: action)
}
}
class Coordinator: NSObject, UIGestureRecognizerDelegate {
var action: () -> Void
init(action: @escaping () -> Void) {
self.action = action
}
@objc func handleGesture(_ recognizer: UITapGestureRecognizer) {
if recognizer.state == .ended {
action()
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
true
}
}
Upvotes: 0
Reputation: 496
I had a similar feature in an app where I wanted to trigger the tap gestures of all the views that overlap. I managed to find another answer that could help, although @jeep is saying that solution does not work very well with lots of nested views.
Paul Hudson also has a relevant article on it too.
Okay so we want a way to allow a tap to trigger the tap gestures of overlapping views — that’s what the above links are about.
But now we just need a multi-tap gesture which is not supported in SwiftUI, but it is in UIKit gesture.
So let’s convert the UIKit gesture to SwiftUI gesture, then use (although this is iOS 18+).
import SwiftUI
struct ContentView: View {
@State private var showSticker = false
var body: some View {
ZStack {
List(0..<100) { index in
Text("Item \(index)")
.padding()
.background(Color.gray.opacity(0.2))
}
if showSticker {
Text("Sticker Label")
.font(.largeTitle)
.padding()
.background(Color.yellow)
.cornerRadius(8)
.transition(.opacity)
}
}
.gesture(MultitouchGesture(onTap: { // iOS 18+
showSticker.toggle()
}))
}
}
fileprivate struct MultitouchGesture: UIGestureRecognizerRepresentable {
// Inputs
let onTap: () -> ()
var numFingers = 3
var numTaps = 2
// Create a coordianator that is in charge of running the onTap method.
// So that we can use @objc here
class Coordinator: NSObject {
private let onTap: () -> ()
init(onTap: @escaping () -> Void) {
self.onTap = onTap
}
@objc func handleTouch() {
onTap()
}
}
func makeCoordinator(converter: CoordinateSpaceConverter) -> Coordinator {
Coordinator(onTap: onTap)
}
// Convert UIKit gestures to SwiftUI
func makeUIGestureRecognizer(context: Context) -> UITapGestureRecognizer {
let tapGesture = UITapGestureRecognizer(
target: context.coordinator,
action: #selector(context.coordinator.handleTouch)
)
tapGesture.numberOfTapsRequired = numTaps
tapGesture.numberOfTouchesRequired = numFingers
return tapGesture
}
}
#Preview {
ContentView()
}
UIGestureRecognizerRepresentable
to covert UIKit gestured to SUI gesturesHopefully my 1.5hr of solving this problem helps!
Upvotes: 0