Details
-
Suggestion
-
Resolution: Unresolved
-
P3: Somewhat important
-
None
-
5.14.0, 6.5
-
None
Description
Hi, doing my first iOS Qt app, and today I tried swiping some QWidgets on my iPhone. While Qt's swipe gestures work fine on my Mac and Windows 10, on the phone it's really tricky to swipe with 3 fingers. Most apps use 1 finger for swipes, seems to be standard on all phones.
Turns out there's an iOS API for recognizing swipes with 1 finger (also with no churn, been the same for 10 years), and it's pretty trivial to integrate that API with Qt's existing QGesture infrastructure.
I ended up with a small .mm file with a function that I call from my QMainWindow's ctor, that registers Apple's swipe API into Qt's QUIView, and in the callback from iOS I post a matching QSwipeGesture. So now I can swipe my widgets with 1 finger on the phone
Would it be possible to add this functionality to Qt itself? As I said, it seems pretty easy, here's the function and the Objective-C method I inject into QUIView (you call the function with your QMainWindow's this and the swipe direction you wish to receive an event for):
bool registerForIOSSwipes(QWidget* w, QSwipeGesture::SwipeDirection sd) { // cast the widget's winId (it's our ticket into the iOS underworld) auto uv = reinterpret_cast<UIView*>(w->winId()); // what we really like is a ptr to Qt's UIView (QUIView) if ("QUIView" != QString::fromNSString(NSStringFromClass([uv class]))) return false; // but it was not to be // have a view, use a lambda to add the 4 different types of swipe gestures auto registerSwipe = [uv](UISwipeGestureRecognizerDirection d) { // new up an iOS gesture recognizer with required # of touches = 1 (Apple default) UISwipeGestureRecognizer* sgr = [[UISwipeGestureRecognizer alloc] initWithTarget:uv action:@selector(handleSwipe:)]; [sgr setDirection:d]; [uv addGestureRecognizer:sgr]; }; if (sd & QSwipeGesture::Left ) registerSwipe(UISwipeGestureRecognizerDirectionLeft ); if (sd & QSwipeGesture::Right) registerSwipe(UISwipeGestureRecognizerDirectionRight); if (sd & QSwipeGesture::Up ) registerSwipe(UISwipeGestureRecognizerDirectionUp ); if (sd & QSwipeGesture::Down ) registerSwipe(UISwipeGestureRecognizerDirectionDown ); // that's all return true; } // some Objective-C red tape so we can inject our gesture recognizer function into Qt's QUIView @interface QUIView : UIView @end // (copied from quiview.h) @implementation QUIView (RedTapeCategory) - (void) handleSwipe: (UISwipeGestureRecognizer*) swipe { // got a swipe, synthesize a swipe flavored Qt gesture event and post it auto sg = new QSwipeGesture; if (UISwipeGestureRecognizerDirectionLeft == swipe.direction) sg->setSwipeAngle(180); if (UISwipeGestureRecognizerDirectionRight == swipe.direction) sg->setSwipeAngle(0); if (UISwipeGestureRecognizerDirectionUp == swipe.direction) sg->setSwipeAngle(90); if (UISwipeGestureRecognizerDirectionDown == swipe.direction) sg->setSwipeAngle(270); auto hotSpot = [swipe locationInView:self]; sg->setHotSpot(QPointF(hotSpot.x,hotSpot.y)); // bon voyage qApp->postEvent(qApp->activeWindow(),new QGestureEvent(QList<QGesture*>{sg})); } @end
Then in my app I receive a normal QSwipeGesture event, say with code like this:
bool MainWindow::event(QEvent *event) { if (event->type() != QEvent::Gesture) return QWidget::event(event); auto e = static_cast<QGestureEvent*>(event); auto g = e->gesture(Qt::SwipeGesture); if (nullptr == g) return QWidget::event(event); auto s = static_cast<QSwipeGesture*>(g); qDebug() << s->hotSpot() << s->horizontalDirection() << s->verticalDirection() << "Z"; return true; }
(I've trimmed some error checking and skipped the #includes/#imports)