-
Notifications
You must be signed in to change notification settings - Fork 6.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(material/slider): fix track animation #25924
Changes from 4 commits
8d76750
2403169
70a47e4
49eb3a2
e1fdf6c
1409cd3
244c1e3
f6cc42f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,7 @@ import { | |
} from '@angular/material/core'; | ||
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; | ||
import {Subscription} from 'rxjs'; | ||
import {take} from 'rxjs/operators'; | ||
import { | ||
_MatThumb, | ||
_MatTickMark, | ||
|
@@ -388,6 +389,8 @@ export class MatSlider | |
/** Whether the slider is rtl. */ | ||
_isRtl: boolean = false; | ||
|
||
private _hasViewInitialized: boolean = false; | ||
|
||
/** | ||
* The width of the tick mark track. | ||
* The tick mark track width is different from full track width | ||
|
@@ -425,6 +428,7 @@ export class MatSlider | |
if (this._platform.isBrowser) { | ||
this._updateDimensions(); | ||
} | ||
|
||
const eInput = this._getInput(_MatThumb.END); | ||
const sInput = this._getInput(_MatThumb.START); | ||
this._isRange = !!eInput && !!sInput; | ||
|
@@ -439,30 +443,42 @@ export class MatSlider | |
|
||
const thumb = this._getThumb(_MatThumb.END); | ||
this._rippleRadius = thumb._ripple.radius; | ||
|
||
this._inputPadding = this._rippleRadius - this._knobRadius; | ||
this._inputOffset = this._knobRadius; | ||
|
||
if (eInput) { | ||
eInput.initProps(); | ||
eInput.initUI(); | ||
} | ||
if (sInput) { | ||
sInput.initProps(); | ||
sInput.initUI(); | ||
} | ||
if (this._isRange) { | ||
(eInput as _MatSliderRangeThumb)._updateMinMax(); | ||
(sInput as _MatSliderRangeThumb)._updateMinMax(); | ||
} | ||
this._updateTrackUI(eInput!); | ||
this._updateTickMarkUI(); | ||
this._updateTickMarkTrackUI(); | ||
this._isRange | ||
? this._initUIRange(eInput as _MatSliderRangeThumb, sInput as _MatSliderRangeThumb) | ||
: this._initUINonRange(eInput!); | ||
|
||
this._observeHostResize(); | ||
this._cdr.detectChanges(); | ||
} | ||
|
||
private _initUINonRange(eInput: _MatSliderThumb): void { | ||
eInput.initProps(); | ||
eInput.initUI(); | ||
|
||
this._updateValueIndicatorUI(eInput); | ||
|
||
this._hasViewInitialized = true; | ||
} | ||
|
||
private _initUIRange(eInput: _MatSliderRangeThumb, sInput: _MatSliderRangeThumb): void { | ||
eInput.initProps(); | ||
eInput.initUI(); | ||
|
||
sInput.initProps(); | ||
sInput.initUI(); | ||
|
||
eInput._updateMinMax(); | ||
sInput._updateMinMax(); | ||
|
||
this._updateValueIndicatorUI(eInput); | ||
this._updateValueIndicatorUI(sInput); | ||
|
||
this._hasViewInitialized = true; | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this._dirChangeSubscription.unsubscribe(); | ||
this._resizeObserver?.disconnect(); | ||
|
@@ -555,10 +571,22 @@ export class MatSlider | |
transformOrigin: string; | ||
}): void { | ||
const trackStyle = this._trackActive.nativeElement.style; | ||
const animationOriginChanged = | ||
styles.left !== trackStyle.left && styles.right !== trackStyle.right; | ||
|
||
trackStyle.left = styles.left; | ||
trackStyle.right = styles.right; | ||
trackStyle.transform = styles.transform; | ||
trackStyle.transformOrigin = styles.transformOrigin; | ||
|
||
if (animationOriginChanged) { | ||
this._elementRef.nativeElement.classList.add('mat-mdc-slider-disable-track-animation'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part seems a little complicated to me. Does the issue happen when the user is dragging? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is kind of a gross problem so apologies for the long description The issue happens when a user alternates clicks between the two thumbs. This causes the track to change which thumb it's animating from, which is whichever thumb is not moving. If the animation is on, there will be a flicker as this change is made. BUT we don't want to disable animations entirely because then the thumb animation will be disabled, too Another layer of complexity is that the track "origin" changing needs to happen immediately to avoid the flicker, but the change in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is firing quite frequently though. If I add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, code was bad. It still fires a lot initially, but I think it's firing for all of the sliders that are in the other tabs of the demo, too |
||
this._ngZone.onStable.pipe(take(1)).subscribe(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure whether we want to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried switching to using requestAnimationFrame but it seems to have issues with the timing causing the active tracks animation to be inconsistent with the thumb. Is there another way to know when the changes have been rendered so I can be sure to get the timing right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, let's leave it for now. The alternatives would be a |
||
this._elementRef.nativeElement.classList.remove('mat-mdc-slider-disable-track-animation'); | ||
trackStyle.transform = styles.transform; | ||
}); | ||
} else { | ||
trackStyle.transform = styles.transform; | ||
} | ||
} | ||
|
||
/** Returns the translateX positioning for a tick mark based on it's index. */ | ||
|
@@ -571,6 +599,10 @@ export class MatSlider | |
// Handlers for updating the slider ui. | ||
|
||
_onTranslateXChange(source: _MatSliderThumb): void { | ||
if (!this._hasViewInitialized) { | ||
return; | ||
} | ||
|
||
this._updateThumbUI(source); | ||
this._updateTrackUI(source); | ||
this._updateOverlappingThumbUI(source as _MatSliderRangeThumb); | ||
|
@@ -580,23 +612,39 @@ export class MatSlider | |
input1: _MatSliderRangeThumb, | ||
input2: _MatSliderRangeThumb, | ||
): void { | ||
if (!this._hasViewInitialized) { | ||
return; | ||
} | ||
|
||
input1._updateThumbUIByValue(); | ||
input2._updateThumbUIByValue(); | ||
} | ||
|
||
_onValueChange(source: _MatSliderThumb): void { | ||
if (!this._hasViewInitialized) { | ||
return; | ||
} | ||
|
||
this._updateValueIndicatorUI(source); | ||
this._updateTickMarkUI(); | ||
this._cdr.detectChanges(); | ||
} | ||
|
||
_onMinMaxOrStepChange(): void { | ||
if (!this._hasViewInitialized) { | ||
return; | ||
} | ||
|
||
this._updateTickMarkUI(); | ||
this._updateTickMarkTrackUI(); | ||
this._cdr.markForCheck(); | ||
} | ||
|
||
_onResize(): void { | ||
if (!this._hasViewInitialized) { | ||
return; | ||
} | ||
|
||
this._updateDimensions(); | ||
if (this._isRange) { | ||
const eInput = this._getInput(_MatThumb.END) as _MatSliderRangeThumb; | ||
|
@@ -693,7 +741,11 @@ export class MatSlider | |
} | ||
|
||
const valuetext = this.displayWith(source.value); | ||
source._valuetext = valuetext; | ||
|
||
if (this._hasViewInitialized) { | ||
source._valuetext = valuetext; | ||
} | ||
|
||
if (this.discrete) { | ||
source.thumbPosition === _MatThumb.START | ||
? (this.startValueIndicatorText = valuetext) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still fires for all the sliders on init. Can we avoid it? My understanding is that the problem only happens when the user is interacting which when it's happening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little ugly but I got this working. The issue with the slider is that changes to properties automatically triggers UI updates. I added a boolean for checking whether the props has been initialized so that those UI updates don't get automatically triggered until the properties are done getting set up