Skip to content

Commit c9b60ce

Browse files
committed
virtual-scroll: add onContentRendered hook to VirtualScrollStrategy
1 parent ba64d89 commit c9b60ce

File tree

4 files changed

+40
-7
lines changed

4 files changed

+40
-7
lines changed

src/cdk-experimental/scrolling/auto-size-virtual-scroll.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,10 @@ export class ItemSizeAverager {
3939
* @param size The measured size of the given range in pixels.
4040
*/
4141
addSample(range: ListRange, size: number) {
42-
const weight = range.end - range.start;
43-
const newTotalWeight = this._totalWeight + weight;
42+
const newTotalWeight = this._totalWeight + range.end - range.start;
4443
if (newTotalWeight) {
4544
const newAverageItemSize =
46-
(size * weight + this._averageItemSize * this._totalWeight) / newTotalWeight;
45+
(size + this._averageItemSize * this._totalWeight) / newTotalWeight;
4746
if (newAverageItemSize) {
4847
this._averageItemSize = newAverageItemSize;
4948
this._totalWeight = newTotalWeight;
@@ -87,7 +86,6 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
8786
*/
8887
attach(viewport: CdkVirtualScrollViewport) {
8988
this._viewport = viewport;
90-
this._updateTotalContentSize();
9189
this._renderContentForOffset(this._viewport.measureScrollOffset());
9290
}
9391

@@ -106,11 +104,20 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
106104
/** Called when the length of the data changes. */
107105
onDataLengthChanged() {
108106
if (this._viewport) {
109-
this._updateTotalContentSize();
110107
this._renderContentForOffset(this._viewport.measureScrollOffset());
111108
}
112109
}
113110

111+
/** Called when the range of items rendered in the DOM has changed. */
112+
onContentRendered() {
113+
if (this._viewport) {
114+
const renderedContentSize = this._viewport.measureRenderedContentSize();
115+
this._averager.addSample(
116+
this._viewport.getRenderedRange(), renderedContentSize);
117+
this._updateTotalContentSize(renderedContentSize);
118+
}
119+
}
120+
114121
/**
115122
* Update the buffer parameters.
116123
* @param minBufferPx The minimum amount of buffer rendered beyond the viewport (in pixels).
@@ -179,9 +186,13 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
179186
}
180187

181188
/** Update the viewport's total content size. */
182-
private _updateTotalContentSize() {
189+
private _updateTotalContentSize(renderedContentSize) {
183190
const viewport = this._viewport!;
184-
viewport.setTotalContentSize(viewport.getDataLength() * this._averager.getAverageItemSize());
191+
const renderedRange = viewport.getRenderedRange();
192+
const totalSize = renderedContentSize +
193+
(viewport.getDataLength() - (renderedRange.end - renderedRange.start)) *
194+
this._averager.getAverageItemSize();
195+
viewport.setTotalContentSize(totalSize);
185196
}
186197
}
187198

src/cdk-experimental/scrolling/fixed-size-virtual-scroll.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ export class FixedSizeVirtualScrollStrategy implements VirtualScrollStrategy {
7070
this._updateRenderedRange();
7171
}
7272

73+
/** Called when the range of items rendered in the DOM has changed. */
74+
onContentRendered() { /* no-op */ }
75+
7376
/** Update the viewport's total content size. */
7477
private _updateTotalContentSize() {
7578
if (!this._viewport) {

src/cdk-experimental/scrolling/virtual-scroll-strategy.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,7 @@ export interface VirtualScrollStrategy {
3131

3232
/** Called when the length of the data changes. */
3333
onDataLengthChanged();
34+
35+
/** Called when the range of items rendered in the DOM has changed. */
36+
onContentRendered();
3437
}

src/cdk-experimental/scrolling/virtual-scroll-viewport.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
import {Observable} from 'rxjs/Observable';
2424
import {fromEvent} from 'rxjs/observable/fromEvent';
2525
import {sampleTime} from 'rxjs/operators/sampleTime';
26+
import {take} from 'rxjs/operators/take';
2627
import {takeUntil} from 'rxjs/operators/takeUntil';
2728
import {animationFrame} from 'rxjs/scheduler/animationFrame';
2829
import {Subject} from 'rxjs/Subject';
@@ -99,6 +100,11 @@ export class CdkVirtualScrollViewport implements OnInit, OnDestroy {
99100
return this._viewportSize;
100101
}
101102

103+
/** Get the current rendered range of items. */
104+
getRenderedRange(): ListRange {
105+
return this._renderedRange;
106+
}
107+
102108
// TODO(mmalebra): Consider calling `detectChanges()` directly rather than the methods below.
103109

104110
/**
@@ -122,6 +128,9 @@ export class CdkVirtualScrollViewport implements OnInit, OnDestroy {
122128
this._ngZone.run(() => {
123129
this._renderedRangeSubject.next(this._renderedRange = range);
124130
this._changeDetectorRef.markForCheck();
131+
this._ngZone.runOutsideAngular(() => this._ngZone.onStable.pipe(take(1)).subscribe(() => {
132+
this._scrollStrategy.onContentRendered();
133+
}));
125134
});
126135
}
127136
}
@@ -169,6 +178,13 @@ export class CdkVirtualScrollViewport implements OnInit, OnDestroy {
169178
this.elementRef.nativeElement.scrollLeft : this.elementRef.nativeElement.scrollTop;
170179
}
171180

181+
/** Measure the combined size of all of the rendered items. */
182+
measureRenderedContentSize() {
183+
return this.orientation === 'horizontal' ?
184+
this._contentWrapper.nativeElement.offsetWidth :
185+
this._contentWrapper.nativeElement.offsetHeight;
186+
}
187+
172188
ngOnInit() {
173189
Promise.resolve().then(() => {
174190
this._viewportSize = this.orientation === 'horizontal' ?

0 commit comments

Comments
 (0)