Creating (and Responding to) Custom Gestures in Ionic 2
tl;dr
If you’re like me, you might be thinking “stop typing words, I just want to see the code!”. Well, okay. Here it is.
Background
I was recently working on an app. One one screen, we wanted to create this interaction with some text on the page:
- Pressing the text would highlight the text
- Letting go would un-highlight the text
- Pressing the text for a long time would allow you to see some additional details about the text (in our case, take the user to a different screen)
Some additional contraints we faced:
- Simply “tapping” the text should not highlight anything (so we couldn’t use the ionic
(tap)="action()"
directive). - The default
(press)
directive used a 250ms delay, which seemed a little laggy. We wanted to make ours shorter - As far as we could find, the default
(press)
directive didn’t allow for us to easily respond to releasing the press (press-up).
Our desired behavior will look something like this:
Quick Press (highlight on press, unhighlight on release):
Long Press (View Details):
So basically, we needed 2 custom directives:
- A quick-press, with our own timeout (somewhere between the default
tap
andpress
), where we could respond to press and press-up events. - A long-press, where we could wait and then show the detail page.
The Code:
There are 4 main things to do:
1. Create the 2 custom directives:
quick-press.directive.ts:
import { Directive, ElementRef, OnInit, OnDestroy, Output, EventEmitter } from '@angular/core'
import { Gesture } from 'ionic-angular/gestures/gesture'
declare var Hammer;
@Directive({
selector: '[quickPress]'
})
export class QuickPressDirective implements OnInit, OnDestroy {
el: HTMLElement;
pressGesture: Gesture;
@Output('quickPress') onPress: EventEmitter<any> = new EventEmitter();
@Output('quickPressUp') onPressUp: EventEmitter<any> = new EventEmitter();
constructor(el: ElementRef) {
this.el = el.nativeElement;
}
ngOnInit() {
const pressOptions = {
recognizers: [
[Hammer.Press, { time: 100 }]
]
};
this.pressGesture = new Gesture(this.el, pressOptions);
this.pressGesture.listen();
this.pressGesture.on('pressup', e => {
this.onPressUp.emit(e);
});
this.pressGesture.on('press', e => {
this.onPress.emit(e);
});
}
ngOnDestroy() {
this.pressGesture.destroy();
}
}
long-press.directive.ts:
(I’m omitting the code for this, because it is literally the same as above, but substitute “quick” for “long”, and change the press options to time: 1000
or whatever time you like. The exported class is LongPressDirective
2. Add the directives to your app.module.ts
file:
app.module.ts:
/*
import { Everything } from './everywhere'
... etc.
*/
// import the directives:
import { LongPressDirective } from '../directives/long-press.directive'
import { QuickPressDirective } from '../directives/quick-press.directive'
/*...*/
// declare the directives:
@NgModule({
declarations: [
LongPressDirective,
QuickPressDirective,
/*...*/
],
/*...*/
})
3. Write callbacks in some component:
my-component.ts:
@Component({
selector: 'hot-off-the-press',
templateUrl: 'my-component.html'
})
export class MyComponent {
/*...*/
quickPressed() {
console.log('quick pressed!')
}
quickPressUpped() {
console.log('quick press upped!')
}
longPressed() {
console.log('long press!')
}
}
And probably do something cooler, but you get the idea.
4. Connect the directives to the callbacks in the template:
my-component.html:
<div (longPress)="longPressed()" (quickPress)="quickPressed()" (quickPressUp)="quickPressUpped()">
<!-- ... -->
</div>
Note: you can also pass whatever arguments to these functions, including $event
, which is emitted by the directives. We didn’t need them in our case.
Other Articles/Blogs/Docs
There are a few great articles about creating custom events. Here are a few that helped me the most. They definitely go into more detail on some aspects, so check them out:
- The “OG” Ionic Gesture Post by Rob Louie
- The Ionic Documentation on Gestures (A little sparse though)
- This SO Post, which really gave me a breakthrough on using EventEmitter/callbacks.
- Article by Josh Morony on custom gesture directives, animation and data-binding.
- HammerJS docs – this is where I learned of the
'pressup'
event. Explore it for more customization. - Ionic Gesture Source on GitHub
Wrap Up
That is all. I hope it was helpful. Here is a gist with slightly more concise code. If you liked it, hated it, have questions or suggestions, let me know in the comments below! (Just kidding, this site doesn’t support comments yet. Email me or “star” the gist though!)
- tyguy