mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-24 23:01:57 +08:00
@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { App } from '../app/app';
|
||||
import { Config } from '../../config/config';
|
||||
@ -17,6 +17,14 @@ import { ViewController } from '../../navigation/view-controller';
|
||||
export { ScrollEvent } from '../../util/scroll-view';
|
||||
|
||||
|
||||
export class EventEmitterProxy<T> extends EventEmitter<T> {
|
||||
onSubscribe: Function;
|
||||
subscribe(generatorOrNext?: any, error?: any, complete?: any): any {
|
||||
this.onSubscribe();
|
||||
return super.subscribe(generatorOrNext, error, complete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Content
|
||||
* @description
|
||||
@ -125,7 +133,7 @@ export { ScrollEvent } from '../../util/scroll-view';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class Content extends Ion implements OnDestroy {
|
||||
export class Content extends Ion implements OnDestroy, AfterViewInit {
|
||||
/** @internal */
|
||||
_cTop: number;
|
||||
/** @internal */
|
||||
@ -312,17 +320,17 @@ export class Content extends Ion implements OnDestroy {
|
||||
/**
|
||||
* @output {ScrollEvent} Emitted when the scrolling first starts.
|
||||
*/
|
||||
@Output() ionScrollStart: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();
|
||||
@Output() ionScrollStart: EventEmitterProxy<ScrollEvent> = new EventEmitterProxy<ScrollEvent>();
|
||||
|
||||
/**
|
||||
* @output {ScrollEvent} Emitted on every scroll event.
|
||||
*/
|
||||
@Output() ionScroll: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();
|
||||
@Output() ionScroll: EventEmitterProxy<ScrollEvent> = new EventEmitterProxy<ScrollEvent>();
|
||||
|
||||
/**
|
||||
* @output {ScrollEvent} Emitted when scrolling ends.
|
||||
*/
|
||||
@Output() ionScrollEnd: EventEmitter<ScrollEvent> = new EventEmitter<ScrollEvent>();
|
||||
@Output() ionScrollEnd: EventEmitterProxy<ScrollEvent> = new EventEmitterProxy<ScrollEvent>();
|
||||
|
||||
|
||||
constructor(
|
||||
@ -339,6 +347,11 @@ export class Content extends Ion implements OnDestroy {
|
||||
) {
|
||||
super(config, elementRef, renderer, 'content');
|
||||
|
||||
let enableScrollListener = this.enableScrollListener.bind(this);
|
||||
this.ionScroll.onSubscribe = enableScrollListener;
|
||||
this.ionScrollStart.onSubscribe = enableScrollListener;
|
||||
this.ionScrollEnd.onSubscribe = enableScrollListener;
|
||||
|
||||
this.statusbarPadding = config.getBoolean('statusbarPadding', false);
|
||||
this._imgReqBfr = config.getNumber('imgRequestBuffer', 1400);
|
||||
this._imgRndBfr = config.getNumber('imgRenderBuffer', 400);
|
||||
@ -348,7 +361,8 @@ export class Content extends Ion implements OnDestroy {
|
||||
// goal is to completely remove this when iOS
|
||||
// fully supports scroll events
|
||||
// listen to JS scroll events
|
||||
this._scroll = new ScrollView(_plt, _dom, config.getBoolean('virtualScrollEventAssist'));
|
||||
const jsScroll = config.getBoolean('virtualScrollEventAssist');
|
||||
this._scroll = new ScrollView(_app, _plt, _dom, jsScroll);
|
||||
|
||||
while (navCtrl) {
|
||||
if (isTabs(<any>navCtrl)) {
|
||||
@ -383,7 +397,7 @@ export class Content extends Ion implements OnDestroy {
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
enableScrollListener() {
|
||||
ngAfterViewInit() {
|
||||
assert(this.getFixedElement(), 'fixed element was not found');
|
||||
assert(this.getScrollElement(), 'scroll element was not found');
|
||||
|
||||
@ -398,9 +412,6 @@ export class Content extends Ion implements OnDestroy {
|
||||
|
||||
// subscribe to every scroll move
|
||||
scroll.onScroll = (ev) => {
|
||||
// remind the app that it's currently scrolling
|
||||
this._app.setScrolling();
|
||||
|
||||
// emit to all of our other friends things be scrolling
|
||||
this.ionScroll.emit(ev);
|
||||
|
||||
@ -413,8 +424,13 @@ export class Content extends Ion implements OnDestroy {
|
||||
|
||||
this.imgsUpdate();
|
||||
};
|
||||
}
|
||||
|
||||
scroll.setEnabled();
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
enableScrollListener() {
|
||||
this._scroll.eventsEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -371,7 +371,6 @@ export class InfiniteScroll {
|
||||
if (shouldListen) {
|
||||
if (!this._scLsn) {
|
||||
this._scLsn = this._content.ionScroll.subscribe(this._onScroll.bind(this));
|
||||
this._content.enableScrollListener();
|
||||
}
|
||||
} else {
|
||||
this._scLsn && this._scLsn.unsubscribe();
|
||||
|
@ -709,7 +709,6 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy {
|
||||
this._resizeSub = this._plt.resize.subscribe(this.resize.bind(this));
|
||||
this._scrollSub = this._content.ionScroll.subscribe(this.scrollUpdate.bind(this));
|
||||
this._scrollEndSub = this._content.ionScrollEnd.subscribe(this.scrollEnd.bind(this));
|
||||
this._content.enableScrollListener();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,8 +137,8 @@ export function setupEvents(plt: Platform, dom: DomController): Events {
|
||||
let contentEle = <any>el.closest('.scroll-content');
|
||||
if (contentEle) {
|
||||
var style = contentEle.style;
|
||||
var scroll = new ScrollView(plt, dom, false);
|
||||
scroll.init(contentEle, 0, 0);
|
||||
var scroll = new ScrollView(null, plt, dom, false);
|
||||
scroll._el = contentEle;
|
||||
// We need to stop scrolling if it's happening and scroll up
|
||||
|
||||
style['WebkitBackfaceVisibility'] = 'hidden';
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
import { assert } from './util';
|
||||
import { App } from '../components/app/app';
|
||||
import { DomController, DomCallback } from '../platform/dom-controller';
|
||||
import { Platform, EventListenerOptions } from '../platform/platform';
|
||||
import { pointerCoord } from './dom';
|
||||
@ -12,11 +13,11 @@ export class ScrollView {
|
||||
onScroll: (ev: ScrollEvent) => void;
|
||||
onScrollEnd: (ev: ScrollEvent) => void;
|
||||
initialized: boolean = false;
|
||||
enabled: boolean = false;
|
||||
eventsEnabled: boolean = false;
|
||||
contentTop: number;
|
||||
contentBottom: number;
|
||||
|
||||
private _el: HTMLElement;
|
||||
_el: HTMLElement;
|
||||
private _js: boolean;
|
||||
private _t: number = 0;
|
||||
private _l: number = 0;
|
||||
@ -25,6 +26,7 @@ export class ScrollView {
|
||||
|
||||
|
||||
constructor(
|
||||
private _app: App,
|
||||
private _plt: Platform,
|
||||
private _dom: DomController,
|
||||
virtualScrollEventAssist: boolean
|
||||
@ -60,35 +62,19 @@ export class ScrollView {
|
||||
|
||||
if (!this.initialized) {
|
||||
this.initialized = true;
|
||||
|
||||
if (this.enabled) {
|
||||
this.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setEnabled() {
|
||||
if (!this.enabled) {
|
||||
this.enabled = true;
|
||||
if (this.initialized) {
|
||||
this.enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enable() {
|
||||
assert(this.initialized, 'scroll must be initialized');
|
||||
assert(this.enabled, 'scroll-view must be enabled');
|
||||
assert(this._el, 'scroll-view, element can not be null');
|
||||
|
||||
if (this._js) {
|
||||
this.enableJsScroll();
|
||||
} else {
|
||||
this.enableNativeScrolling();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enableNativeScrolling() {
|
||||
assert(this.onScrollStart, 'onScrollStart is not defined');
|
||||
assert(this.onScroll, 'onScroll is not defined');
|
||||
assert(this.onScrollEnd, 'onScrollEnd is not defined');
|
||||
|
||||
this._js = false;
|
||||
if (!this._el) {
|
||||
return;
|
||||
@ -101,6 +87,14 @@ export class ScrollView {
|
||||
const positions: number[] = [];
|
||||
|
||||
function scrollCallback(scrollEvent: UIEvent) {
|
||||
// remind the app that it's currently scrolling
|
||||
self._app.setScrolling();
|
||||
|
||||
// if events are disabled, we do nothing
|
||||
if (!self.eventsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
ev.timeStamp = scrollEvent.timeStamp;
|
||||
// Event.timeStamp is 0 in firefox
|
||||
if (!ev.timeStamp) {
|
||||
@ -151,13 +145,12 @@ export class ScrollView {
|
||||
|
||||
if (startPos !== endPos) {
|
||||
// compute relative movement between these two points
|
||||
var timeOffset = (positions[endPos] - positions[startPos]);
|
||||
var movedTop = (positions[startPos - 2] - positions[endPos - 2]);
|
||||
var movedLeft = (positions[startPos - 1] - positions[endPos - 1]);
|
||||
|
||||
var factor = FRAME_MS / (positions[endPos] - positions[startPos]);
|
||||
// based on XXms compute the movement to apply for each render step
|
||||
ev.velocityY = ((movedTop / timeOffset) * FRAME_MS);
|
||||
ev.velocityX = ((movedLeft / timeOffset) * FRAME_MS);
|
||||
ev.velocityY = movedTop * factor;
|
||||
ev.velocityX = movedLeft * factor;
|
||||
|
||||
// figure out which direction we're scrolling
|
||||
ev.directionY = (movedTop > 0 ? 'up' : 'down');
|
||||
@ -546,11 +539,10 @@ export class ScrollView {
|
||||
this._endTmr && this._dom.cancel(this._endTmr);
|
||||
this._lsn && this._lsn();
|
||||
|
||||
this.onScrollStart = this.onScroll = this.onScrollEnd = null;
|
||||
|
||||
let ev = this.ev;
|
||||
ev.domWrite = ev.contentElement = ev.fixedElement = ev.scrollElement = ev.headerElement = null;
|
||||
this._lsn = this._el = this._dom = this.ev = ev = null;
|
||||
this.onScrollStart = this.onScroll = this.onScrollEnd = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user