mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(cdk/virtual-scroll): fix subpixel rounding errors on hdpi… (#16269)
* fix(cdk/virtual-scroll): fix subpixel rounding errors on hdpi screens Using `transform` appears to cause rounding errors that can accumulate and become significant after scrolling through a large number of items. Switching to `width` / `height` corrects this. * don't recalulate height/width during every change detection
This commit is contained in:
@@ -9,4 +9,5 @@
|
||||
Spacer used to force the scrolling container to the correct size for the *total* number of items
|
||||
so that the scrollbar captures the size of the entire data set.
|
||||
-->
|
||||
<div class="cdk-virtual-scroll-spacer" [style.transform]="_totalContentSizeTransform"></div>
|
||||
<div class="cdk-virtual-scroll-spacer"
|
||||
[style.width]="_totalContentWidth" [style.height]="_totalContentHeight"></div>
|
||||
|
||||
@@ -71,7 +71,17 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
|
||||
private _renderedRangeSubject = new Subject<ListRange>();
|
||||
|
||||
/** The direction the viewport scrolls. */
|
||||
@Input() orientation: 'horizontal' | 'vertical' = 'vertical';
|
||||
@Input()
|
||||
get orientation() {
|
||||
return this._orientation;
|
||||
}
|
||||
set orientation(orientation: 'horizontal' | 'vertical') {
|
||||
if (this._orientation !== orientation) {
|
||||
this._orientation = orientation;
|
||||
this._calculateSpacerSize();
|
||||
}
|
||||
}
|
||||
private _orientation: 'horizontal' | 'vertical' = 'vertical';
|
||||
|
||||
// Note: we don't use the typical EventEmitter here because we need to subscribe to the scroll
|
||||
// strategy lazily (i.e. only if the user is actually listening to the events). We do this because
|
||||
@@ -89,17 +99,17 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
|
||||
/** A stream that emits whenever the rendered range changes. */
|
||||
renderedRangeStream: Observable<ListRange> = this._renderedRangeSubject.asObservable();
|
||||
|
||||
/**
|
||||
* The transform used to scale the spacer to the same size as all content, including content that
|
||||
* is not currently rendered.
|
||||
*/
|
||||
_totalContentSizeTransform = '';
|
||||
|
||||
/**
|
||||
* The total size of all content (in pixels), including content that is not currently rendered.
|
||||
*/
|
||||
private _totalContentSize = 0;
|
||||
|
||||
/** A string representing the `style.width` property value to be used for the spacer element. */
|
||||
_totalContentWidth = '';
|
||||
|
||||
/** A string representing the `style.height` property value to be used for the spacer element. */
|
||||
_totalContentHeight = '';
|
||||
|
||||
/**
|
||||
* The CSS transform applied to the rendered subset of items so that they appear within the bounds
|
||||
* of the visible viewport.
|
||||
@@ -238,8 +248,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
|
||||
setTotalContentSize(size: number) {
|
||||
if (this._totalContentSize !== size) {
|
||||
this._totalContentSize = size;
|
||||
const axis = this.orientation == 'horizontal' ? 'X' : 'Y';
|
||||
this._totalContentSizeTransform = `scale${axis}(${this._totalContentSize})`;
|
||||
this._calculateSpacerSize();
|
||||
this._markChangeDetectionNeeded();
|
||||
}
|
||||
}
|
||||
@@ -398,4 +407,12 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O
|
||||
fn();
|
||||
}
|
||||
}
|
||||
|
||||
/** Calculates the `style.width` and `style.height` for the spacer element. */
|
||||
private _calculateSpacerSize() {
|
||||
this._totalContentHeight =
|
||||
this.orientation === 'horizontal' ? '' : `${this._totalContentSize}px`;
|
||||
this._totalContentWidth =
|
||||
this.orientation === 'horizontal' ? `${this._totalContentSize}px` : '';
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -90,7 +90,8 @@ export declare type CdkVirtualForOfContext<T> = {
|
||||
|
||||
export declare class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, OnDestroy {
|
||||
_contentWrapper: ElementRef<HTMLElement>;
|
||||
_totalContentSizeTransform: string;
|
||||
_totalContentHeight: string;
|
||||
_totalContentWidth: string;
|
||||
elementRef: ElementRef<HTMLElement>;
|
||||
orientation: 'horizontal' | 'vertical';
|
||||
renderedRangeStream: Observable<ListRange>;
|
||||
|
||||
Reference in New Issue
Block a user