Skip to content

Commit ded4bab

Browse files
authored
fix(material/slider): fix track animation (#25924)
* fix(material/slider): fix track animation * fixes an issue where the slider track active would flicker when switching between thumbs on a range slider * fixup! fix(material/slider): fix track animation * fixup! fix(material/slider): fix track animation * fixup! fix(material/slider): fix track animation * fixup! fix(material/slider): fix track animation * fixup! fix(material/slider): fix track animation * fixup! fix(material/slider): fix track animation * fixup! fix(material/slider): fix track animation
1 parent 952cf06 commit ded4bab

File tree

2 files changed

+93
-16
lines changed

2 files changed

+93
-16
lines changed

src/material/slider/slider.scss

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ $mat-slider-horizontal-margin: 8px !default;
5555
.mdc-slider__track--active_fill {
5656
transition-duration: 80ms;
5757
}
58+
59+
&.mat-mdc-slider-disable-track-animation {
60+
.mdc-slider__track--active_fill {
61+
transition-duration: 0ms;
62+
}
63+
}
5864
}
5965

6066
// We need to repeat these styles to override discrete slider styling.
@@ -69,6 +75,12 @@ $mat-slider-horizontal-margin: 8px !default;
6975
.mdc-slider__track--active_fill {
7076
transition-duration: 80ms;
7177
}
78+
79+
&.mat-mdc-slider-disable-track-animation {
80+
.mdc-slider__track--active_fill {
81+
transition-duration: 0ms;
82+
}
83+
}
7284
}
7385

7486
.mdc-slider__track,
@@ -93,7 +105,8 @@ $mat-slider-horizontal-margin: 8px !default;
93105
background-color: var(--mat-mdc-slider-hover-ripple-color, transparent);
94106
}
95107

96-
.mat-mdc-slider-focus-ripple, .mat-mdc-slider-active-ripple {
108+
.mat-mdc-slider-focus-ripple,
109+
.mat-mdc-slider-active-ripple {
97110
background-color: var(--mat-mdc-slider-focus-ripple-color, transparent);
98111
}
99112
}

src/material/slider/slider.ts

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import {
4141
} from '@angular/material/core';
4242
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
4343
import {Subscription} from 'rxjs';
44+
import {take} from 'rxjs/operators';
4445
import {
4546
_MatThumb,
4647
_MatTickMark,
@@ -388,6 +389,8 @@ export class MatSlider
388389
/** Whether the slider is rtl. */
389390
_isRtl: boolean = false;
390391

392+
private _hasViewInitialized: boolean = false;
393+
391394
/**
392395
* The width of the tick mark track.
393396
* The tick mark track width is different from full track width
@@ -425,9 +428,11 @@ export class MatSlider
425428
if (this._platform.isBrowser) {
426429
this._updateDimensions();
427430
}
431+
428432
const eInput = this._getInput(_MatThumb.END);
429433
const sInput = this._getInput(_MatThumb.START);
430434
this._isRange = !!eInput && !!sInput;
435+
this._cdr.detectChanges();
431436

432437
if (typeof ngDevMode === 'undefined' || ngDevMode) {
433438
_validateInputs(
@@ -439,22 +444,13 @@ export class MatSlider
439444

440445
const thumb = this._getThumb(_MatThumb.END);
441446
this._rippleRadius = thumb._ripple.radius;
442-
443447
this._inputPadding = this._rippleRadius - this._knobRadius;
444448
this._inputOffset = this._knobRadius;
445449

446-
if (eInput) {
447-
eInput.initProps();
448-
eInput.initUI();
449-
}
450-
if (sInput) {
451-
sInput.initProps();
452-
sInput.initUI();
453-
}
454-
if (this._isRange) {
455-
(eInput as _MatSliderRangeThumb)._updateMinMax();
456-
(sInput as _MatSliderRangeThumb)._updateMinMax();
457-
}
450+
this._isRange
451+
? this._initUIRange(eInput as _MatSliderRangeThumb, sInput as _MatSliderRangeThumb)
452+
: this._initUINonRange(eInput!);
453+
458454
this._updateTrackUI(eInput!);
459455
this._updateTickMarkUI();
460456
this._updateTickMarkTrackUI();
@@ -463,6 +459,38 @@ export class MatSlider
463459
this._cdr.detectChanges();
464460
}
465461

462+
private _initUINonRange(eInput: _MatSliderThumb): void {
463+
eInput.initProps();
464+
eInput.initUI();
465+
466+
this._updateValueIndicatorUI(eInput);
467+
468+
this._hasViewInitialized = true;
469+
eInput._updateThumbUIByValue();
470+
}
471+
472+
private _initUIRange(eInput: _MatSliderRangeThumb, sInput: _MatSliderRangeThumb): void {
473+
eInput.initProps();
474+
eInput.initUI();
475+
476+
sInput.initProps();
477+
sInput.initUI();
478+
479+
eInput._updateMinMax();
480+
sInput._updateMinMax();
481+
482+
eInput._updateStaticStyles();
483+
sInput._updateStaticStyles();
484+
485+
this._updateValueIndicatorUI(eInput);
486+
this._updateValueIndicatorUI(sInput);
487+
488+
this._hasViewInitialized = true;
489+
490+
eInput._updateThumbUIByValue();
491+
sInput._updateThumbUIByValue();
492+
}
493+
466494
ngOnDestroy(): void {
467495
this._dirChangeSubscription.unsubscribe();
468496
this._resizeObserver?.disconnect();
@@ -555,10 +583,22 @@ export class MatSlider
555583
transformOrigin: string;
556584
}): void {
557585
const trackStyle = this._trackActive.nativeElement.style;
586+
const animationOriginChanged =
587+
styles.left !== trackStyle.left && styles.right !== trackStyle.right;
588+
558589
trackStyle.left = styles.left;
559590
trackStyle.right = styles.right;
560-
trackStyle.transform = styles.transform;
561591
trackStyle.transformOrigin = styles.transformOrigin;
592+
593+
if (animationOriginChanged) {
594+
this._elementRef.nativeElement.classList.add('mat-mdc-slider-disable-track-animation');
595+
this._ngZone.onStable.pipe(take(1)).subscribe(() => {
596+
this._elementRef.nativeElement.classList.remove('mat-mdc-slider-disable-track-animation');
597+
trackStyle.transform = styles.transform;
598+
});
599+
} else {
600+
trackStyle.transform = styles.transform;
601+
}
562602
}
563603

564604
/** Returns the translateX positioning for a tick mark based on it's index. */
@@ -571,6 +611,10 @@ export class MatSlider
571611
// Handlers for updating the slider ui.
572612

573613
_onTranslateXChange(source: _MatSliderThumb): void {
614+
if (!this._hasViewInitialized) {
615+
return;
616+
}
617+
574618
this._updateThumbUI(source);
575619
this._updateTrackUI(source);
576620
this._updateOverlappingThumbUI(source as _MatSliderRangeThumb);
@@ -580,23 +624,39 @@ export class MatSlider
580624
input1: _MatSliderRangeThumb,
581625
input2: _MatSliderRangeThumb,
582626
): void {
627+
if (!this._hasViewInitialized) {
628+
return;
629+
}
630+
583631
input1._updateThumbUIByValue();
584632
input2._updateThumbUIByValue();
585633
}
586634

587635
_onValueChange(source: _MatSliderThumb): void {
636+
if (!this._hasViewInitialized) {
637+
return;
638+
}
639+
588640
this._updateValueIndicatorUI(source);
589641
this._updateTickMarkUI();
590642
this._cdr.detectChanges();
591643
}
592644

593645
_onMinMaxOrStepChange(): void {
646+
if (!this._hasViewInitialized) {
647+
return;
648+
}
649+
594650
this._updateTickMarkUI();
595651
this._updateTickMarkTrackUI();
596652
this._cdr.markForCheck();
597653
}
598654

599655
_onResize(): void {
656+
if (!this._hasViewInitialized) {
657+
return;
658+
}
659+
600660
this._updateDimensions();
601661
if (this._isRange) {
602662
const eInput = this._getInput(_MatThumb.END) as _MatSliderRangeThumb;
@@ -693,7 +753,11 @@ export class MatSlider
693753
}
694754

695755
const valuetext = this.displayWith(source.value);
696-
source._valuetext = valuetext;
756+
757+
this._hasViewInitialized
758+
? (source._valuetext = valuetext)
759+
: source._hostElement.setAttribute('aria-valuetext', valuetext);
760+
697761
if (this.discrete) {
698762
source.thumbPosition === _MatThumb.START
699763
? (this.startValueIndicatorText = valuetext)

0 commit comments

Comments
 (0)