Here is a quick stab at swipeable tabs, this time as an Angular attribute directive. I have not had time to continue work on this, but I thought I’d post in case anyone wanted to take it further.
Modify app.module.ts:
import { TabSwipeDirective } from '../some-directory/tabswipe.directive';
...
* Then add TabSwipeDirective to declarations[...] list of NgModule
tabswipe.directive.ts:
import { Directive, ElementRef, Input, Inject, forwardRef } from '@angular/core';
import { Gesture } from 'ionic-angular/gestures/gesture';
import { Tabs, Tab } from 'ionic-angular';
@Directive({
selector: '[tab-swipe]'
})
export class TabSwipeDirective {
@Input('tab-swipe') direction = 'left';
@Input('swipe-threshold') threshold = 40;
private _sourceElementRef: ElementRef;
private _sourceGesture: Gesture;
private _sourceElement: HTMLElement;
private _sourceTab: Tab;
private _destElement: HTMLElement;
private _destTab: Tab;
private _tabIndex = 0;
constructor(el: ElementRef, @Inject(forwardRef(() => Tabs)) private _tabs:Tabs) {
this._sourceElementRef = el;
this._sourceElement = el.nativeElement;
this._sourceGesture = new Gesture(this._sourceElement);
this._sourceGesture.listen();
this._sourceGesture.on('panstart', (ev) => this._panStart(ev));
this._sourceGesture.on('panend', (ev) => this._panEnd(ev));
this._sourceGesture.on('panleft panright', (ev) => this._panMove(ev));
console.log(this._tabs);
}
ngAfterViewInit() {
for (let idx = 0; idx < this._tabs._tabs.length; idx++) {
if (this._tabs._tabs[idx]._tabId === this._sourceElementRef.nativeElement.id) {
this._tabIndex = idx; break;
}
}
this._sourceTab = this._tabs._tabs[this._tabIndex];
}
_panStart(ev) {
if (this.direction === 'left') {
this._destTab = this._tabs._tabs[this._tabIndex+1];
this._destElement = this._destTab._elementRef.nativeElement;
} else if (this.direction === 'right') {
this._destTab = this._tabs._tabs[this._tabIndex-1];
this._destElement = this._destTab._elementRef.nativeElement;
}
}
_panEnd(ev) {
if ((this.direction === 'right' && ( ev.deltaX < this.threshold || ev.deltaX < 0)) ||
(this.direction === 'left' && (-ev.deltaX < this.threshold || ev.deltaX > 0))) {
this._destElement.className.replace(' show-tab','');
this._tabs.select(this._sourceTab);
} else {
this._tabs.select(this._destTab);
}
this._sourceElement.style.transform = 'translate(0px,0px)';
this._destElement.style.transform = 'translate(0px,0px)';
}
_panMove(ev) {
let delta = ev.deltaX;
if (ev.deltaX < 0 && this.direction === 'right') delta = 0;
if (ev.deltaX > 0 && this.direction === 'left') delta = 0;
let offset = 0;
if (this.direction === 'right') {
offset = -this._destElement.offsetWidth;
} else if (this.direction === 'left') {
offset = this._destElement.offsetWidth;
if (-delta > offset) offset = -delta;
}
this._sourceElement.style.transform = 'translate(' + delta + 'px,0px)';
this._destElement.style.transform = 'translate(' + (offset + delta) + 'px,0px)';
this._destElement.className = this._destElement.className.replace(' show-tab','') + ' show-tab';
}
}
Modify your tabs page:
<ion-tabs selectedIndex="1">
<ion-tab [root]="tabContacts" tabIcon="contacts" tab-swipe="left"></ion-tab>
<ion-tab [root]="tabSettings" tabIcon="settings" tab-swipe="right"></ion-tab>
</ion-tabs>
Open issues:
- On first swipe, the other tabs are not loaded, so they are blank.
- Doesn’t always prevent swiping the wrong direction and can get stuck on top-most page.
- Ideally, the ion-header should not move with the page, it should transition in a platform-specific way.
- Doesn’t currently support swiping in both directions for a tab that is in the “middle” of two other tabs.
- The tab-swipe=“left/right” part is supposed to set which direction swipes are available for a particular page, there should also be an ‘auto’ and ‘none’ option.
- Clicking a tab icon doesn’t slide the tabs.
It’s probably buggy in other ways too, but I think if it were completed, this would be a good bridge until this is added to the framework…