Skip to content

Commit 7e9bad5

Browse files
committed
perf(content): scrollview magic activated on demand
1 parent 963cdcb commit 7e9bad5

File tree

5 files changed

+82
-64
lines changed

5 files changed

+82
-64
lines changed

src/components/content/content.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
1+
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, NgZone, OnDestroy, Optional, Output, Renderer, ViewChild, ViewEncapsulation } from '@angular/core';
22

33
import { App } from '../app/app';
44
import { Config } from '../../config/config';
@@ -123,7 +123,7 @@ export { ScrollEvent } from '../../util/scroll-view';
123123
changeDetection: ChangeDetectionStrategy.OnPush,
124124
encapsulation: ViewEncapsulation.None
125125
})
126-
export class Content extends Ion implements OnDestroy, OnInit {
126+
export class Content extends Ion implements OnDestroy {
127127
/** @internal */
128128
_cTop: number;
129129
/** @internal */
@@ -339,7 +339,12 @@ export class Content extends Ion implements OnDestroy, OnInit {
339339
this._imgReqBfr = config.getNumber('imgRequestBuffer', 1400);
340340
this._imgRndBfr = config.getNumber('imgRenderBuffer', 400);
341341
this._imgVelMax = config.getNumber('imgVelocityMax', 3);
342-
this._scroll = new ScrollView(_plt, _dom);
342+
343+
// use JS scrolling for iOS UIWebView
344+
// goal is to completely remove this when iOS
345+
// fully supports scroll events
346+
// listen to JS scroll events
347+
this._scroll = new ScrollView(_plt, _dom, config.getBoolean('virtualScrollEventAssist'));
343348

344349
if (viewCtrl) {
345350
// content has a view controller
@@ -366,7 +371,7 @@ export class Content extends Ion implements OnDestroy, OnInit {
366371
/**
367372
* @private
368373
*/
369-
ngOnInit() {
374+
enableScrollListener() {
370375
assert(this.getFixedElement(), 'fixed element was not found');
371376
assert(this.getScrollElement(), 'scroll element was not found');
372377

@@ -375,27 +380,29 @@ export class Content extends Ion implements OnDestroy, OnInit {
375380
scroll.ev.scrollElement = this.getScrollElement();
376381

377382
// subscribe to the scroll start
378-
scroll.scrollStart.subscribe(ev => {
383+
scroll.onScrollStart = (ev) => {
379384
this.ionScrollStart.emit(ev);
380-
});
385+
};
381386

382387
// subscribe to every scroll move
383-
scroll.scroll.subscribe(ev => {
388+
scroll.onScroll = (ev) => {
384389
// remind the app that it's currently scrolling
385390
this._app.setScrolling();
386391

387392
// emit to all of our other friends things be scrolling
388393
this.ionScroll.emit(ev);
389394

390395
this.imgsUpdate();
391-
});
396+
};
392397

393398
// subscribe to the scroll end
394-
scroll.scrollEnd.subscribe(ev => {
399+
scroll.onScrollEnd = (ev) => {
395400
this.ionScrollEnd.emit(ev);
396401

397402
this.imgsUpdate();
398-
});
403+
};
404+
405+
scroll.setEnabled();
399406
}
400407

401408
/**
@@ -466,13 +473,6 @@ export class Content extends Ion implements OnDestroy, OnInit {
466473
return this._scroll.scrollToBottom(duration);
467474
}
468475

469-
/**
470-
* @private
471-
*/
472-
enableJsScroll() {
473-
this._scroll.enableJsScroll(this._cTop, this._cBottom);
474-
}
475-
476476
/**
477477
* @input {boolean} If true, the content will scroll behind the headers
478478
* and footers. This effect can easily be seen by setting the toolbar

src/components/infinite-scroll/infinite-scroll.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,8 @@ export class InfiniteScroll {
366366
if (this._init) {
367367
if (shouldListen) {
368368
if (!this._scLsn) {
369-
this._scLsn = this._content.ionScroll.subscribe((ev: ScrollEvent) => {
370-
this._onScroll(ev);
371-
});
369+
this._scLsn = this._content.ionScroll.subscribe(this._onScroll.bind(this));
370+
this._content.enableScrollListener();
372371
}
373372
} else {
374373
this._scLsn && this._scLsn.unsubscribe();

src/components/virtual-scroll/virtual-scroll.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -708,17 +708,10 @@ export class VirtualScroll implements DoCheck, AfterContentInit, OnDestroy {
708708
*/
709709
private _listeners() {
710710
if (!this._scrollSub) {
711-
if (this._config.getBoolean('virtualScrollEventAssist')) {
712-
// use JS scrolling for iOS UIWebView
713-
// goal is to completely remove this when iOS
714-
// fully supports scroll events
715-
// listen to JS scroll events
716-
this._content.enableJsScroll();
717-
}
718-
719711
this._resizeSub = this._plt.resize.subscribe(this.resize.bind(this));
720712
this._scrollSub = this._content.ionScroll.subscribe(this.scrollUpdate.bind(this));
721713
this._scrollEndSub = this._content.ionScrollEnd.subscribe(this.scrollEnd.bind(this));
714+
this._content.enableScrollListener();
722715
}
723716
}
724717

src/util/events.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -134,22 +134,23 @@ export function setupEvents(plt: Platform, dom: DomController): Events {
134134
let el = <HTMLElement>doc.elementFromPoint(plt.width() / 2, plt.height() / 2);
135135
if (!el) { return; }
136136

137-
let contentEle = <HTMLElement>el.closest('.scroll-content');
137+
let contentEle = <any>el.closest('.scroll-content');
138138
if (contentEle) {
139-
var scroll = new ScrollView(plt, dom);
139+
var style = contentEle.style;
140+
var scroll = new ScrollView(plt, dom, false);
140141
scroll.init(contentEle, 0, 0);
141142
// We need to stop scrolling if it's happening and scroll up
142143

143-
(<any>contentEle.style)['WebkitBackfaceVisibility'] = 'hidden';
144-
(<any>contentEle.style)['WebkitTransform'] = 'translate3d(0,0,0)';
144+
style['WebkitBackfaceVisibility'] = 'hidden';
145+
style['WebkitTransform'] = 'translate3d(0,0,0)';
145146

146147
dom.write(function() {
147-
contentEle.style.overflow = 'hidden';
148+
style.overflow = 'hidden';
148149

149150
function finish() {
150-
contentEle.style.overflow = '';
151-
(<any>contentEle.style)['WebkitBackfaceVisibility'] = '';
152-
(<any>contentEle.style)['WebkitTransform'] = '';
151+
style.overflow = '';
152+
style['WebkitBackfaceVisibility'] = '';
153+
style['WebkitTransform'] = '';
153154
}
154155

155156
let didScrollTimeout = plt.timeout(() => {

src/util/scroll-view.ts

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Subject } from 'rxjs/Subject';
21

32
import { assert } from './util';
43
import { DomController, DomCallback } from '../platform/dom-controller';
@@ -9,10 +8,13 @@ import { pointerCoord } from './dom';
98
export class ScrollView {
109
ev: ScrollEvent;
1110
isScrolling = false;
12-
scrollStart = new Subject<ScrollEvent>();
13-
scroll = new Subject<ScrollEvent>();
14-
scrollEnd = new Subject<ScrollEvent>();
15-
initialized: boolean;
11+
onScrollStart: (ev: ScrollEvent) => void;
12+
onScroll: (ev: ScrollEvent) => void;
13+
onScrollEnd: (ev: ScrollEvent) => void;
14+
initialized: boolean = false;
15+
enabled: boolean = false;
16+
contentTop: number;
17+
contentBottom: number;
1618

1719
private _el: HTMLElement;
1820
private _js: boolean;
@@ -22,7 +24,12 @@ export class ScrollView {
2224
private _endTmr: Function;
2325

2426

25-
constructor(private _plt: Platform, private _dom: DomController) {
27+
constructor(
28+
private _plt: Platform,
29+
private _dom: DomController,
30+
virtualScrollEventAssist: boolean
31+
) {
32+
this._js = virtualScrollEventAssist;
2633
this.ev = {
2734
timeStamp: 0,
2835
scrollTop: 0,
@@ -41,27 +48,47 @@ export class ScrollView {
4148
velocityX: 0,
4249
directionY: 'down',
4350
directionX: null,
44-
domWrite: function(fn: DomCallback, ctx?: any): void {
45-
_dom.write(fn, ctx);
46-
}
51+
domWrite: _dom.write.bind(_dom)
4752
};
4853
}
4954

5055
init(ele: HTMLElement, contentTop: number, contentBottom: number) {
56+
assert(ele, 'scroll-view, element can not be null');
57+
this._el = ele;
58+
this.initialized = true;
59+
this.contentTop = contentTop;
60+
this.contentBottom = contentBottom;
61+
5162
if (!this.initialized) {
5263
this.initialized = true;
5364

54-
assert(ele, 'scroll-view, element can not be null');
55-
this._el = ele;
65+
if (this.enabled) {
66+
this.enable();
67+
}
68+
}
69+
}
5670

57-
if (this._js) {
58-
this.enableJsScroll(contentTop, contentBottom);
59-
} else {
60-
this.enableNativeScrolling();
71+
setEnabled() {
72+
if (!this.enabled) {
73+
this.enabled = true;
74+
if (this.initialized) {
75+
this.enable();
6176
}
6277
}
6378
}
6479

80+
enable() {
81+
assert(this.initialized, 'scroll must be initialized');
82+
assert(this.enabled, 'scroll-view must be enabled');
83+
assert(this._el, 'scroll-view, element can not be null');
84+
85+
if (this._js) {
86+
this.enableJsScroll();
87+
} else {
88+
this.enableNativeScrolling();
89+
}
90+
}
91+
6592
private enableNativeScrolling() {
6693
this._js = false;
6794
if (!this._el) {
@@ -103,7 +130,7 @@ export class ScrollView {
103130
positions.length = 0;
104131

105132
// emit only on the first scroll event
106-
self.scrollStart.next(ev);
133+
self.onScrollStart(ev);
107134
}
108135

109136
// actively scrolling
@@ -147,13 +174,13 @@ export class ScrollView {
147174
ev.velocityY = ev.velocityX = 0;
148175

149176
// emit that the scroll has ended
150-
self.scrollEnd && self.scrollEnd.next(ev);
177+
self.onScrollEnd(ev);
151178

152179
self._endTmr = null;
153180
}
154181

155182
// emit on each scroll event
156-
self.scroll.next(ev);
183+
self.onScroll(ev);
157184

158185
// debounce for a moment after the last scroll event
159186
self._dom.cancel(self._endTmr);
@@ -181,7 +208,7 @@ export class ScrollView {
181208
* inertia then this can be burned to the ground. iOS's more modern
182209
* WKWebView does not have this issue, only UIWebView does.
183210
*/
184-
enableJsScroll(contentTop: number, contentBottom: number) {
211+
enableJsScroll() {
185212
const self = this;
186213
self._js = true;
187214
const ele = self._el;
@@ -200,7 +227,7 @@ export class ScrollView {
200227
function setMax() {
201228
if (!max) {
202229
// ******** DOM READ ****************
203-
max = ele.scrollHeight - ele.parentElement.offsetHeight + contentTop + contentBottom;
230+
max = ele.scrollHeight - ele.parentElement.offsetHeight + self.contentTop + self.contentBottom;
204231
}
205232
};
206233

@@ -221,7 +248,7 @@ export class ScrollView {
221248
ev.scrollTop = self._t;
222249

223250
// emit on each scroll event
224-
self.scroll.next(ev);
251+
self.onScroll(ev);
225252

226253
self._dom.write(() => {
227254
// ******** DOM WRITE ****************
@@ -240,7 +267,7 @@ export class ScrollView {
240267
ev.velocityY = ev.velocityX = 0;
241268

242269
// emit that the scroll has ended
243-
self.scrollEnd && self.scrollEnd.next(ev);
270+
self.onScrollEnd(ev);
244271
}
245272
});
246273
}
@@ -279,7 +306,7 @@ export class ScrollView {
279306
self.isScrolling = true;
280307

281308
// emit only on the first scroll event
282-
self.scrollStart.next(ev);
309+
self.onScrollStart(ev);
283310
}
284311

285312
self._dom.write(() => {
@@ -295,7 +322,7 @@ export class ScrollView {
295322
if (!positions.length && self.isScrolling) {
296323
self.isScrolling = false;
297324
ev.velocityY = ev.velocityX = 0;
298-
self.scrollEnd && self.scrollEnd.next(ev);
325+
self.onScrollEnd(ev);
299326
return;
300327
}
301328

@@ -333,7 +360,7 @@ export class ScrollView {
333360
} else {
334361
self.isScrolling = false;
335362
ev.velocityY = 0;
336-
self.scrollEnd && self.scrollEnd.next(ev);
363+
self.onScrollEnd(ev);
337364
}
338365

339366
positions.length = 0;
@@ -520,9 +547,7 @@ export class ScrollView {
520547
this._endTmr && this._dom.cancel(this._endTmr);
521548
this._lsn && this._lsn();
522549

523-
this.scrollStart && this.scrollStart.unsubscribe();
524-
this.scroll && this.scroll.unsubscribe();
525-
this.scrollEnd && this.scrollEnd.unsubscribe();
550+
this.onScrollStart = this.onScroll = this.onScrollEnd = null;
526551

527552
let ev = this.ev;
528553
ev.domWrite = ev.contentElement = ev.fixedElement = ev.scrollElement = ev.headerElement = null;

0 commit comments

Comments
 (0)