@@ -68,6 +68,8 @@ abstract class DrawableWithAnimatedVisibilityChange extends Drawable implements
6868 private List <AnimationCallback > animationCallbacks ;
6969 // An internal AnimationCallback which is executed before the user's animation callbacks.
7070 private AnimationCallback internalAnimationCallback ;
71+ // Flag to ignore all external callbacks.
72+ private boolean ignoreCallbacks ;
7173
7274 // A fraction from 0 to 1 indicating the ratio used in drawing, controlled by show/hide animator.
7375 private float growFraction ;
@@ -165,7 +167,7 @@ private void dispatchAnimationStart() {
165167 if (internalAnimationCallback != null ) {
166168 internalAnimationCallback .onAnimationStart (this );
167169 }
168- if (animationCallbacks != null ) {
170+ if (animationCallbacks != null && ! ignoreCallbacks ) {
169171 for (AnimationCallback callback : animationCallbacks ) {
170172 callback .onAnimationStart (this );
171173 }
@@ -177,7 +179,7 @@ private void dispatchAnimationEnd() {
177179 if (internalAnimationCallback != null ) {
178180 internalAnimationCallback .onAnimationEnd (this );
179181 }
180- if (animationCallbacks != null ) {
182+ if (animationCallbacks != null && ! ignoreCallbacks ) {
181183 for (AnimationCallback callback : animationCallbacks ) {
182184 callback .onAnimationEnd (this );
183185 }
@@ -211,48 +213,66 @@ public boolean isHiding() {
211213 return (hideAnimator != null && hideAnimator .isRunning ()) || mockHideAnimationRunning ;
212214 }
213215
214- /** Hides the drawable immediately */
215- public boolean hideNow (){
216+ /** Hides the drawable immediately without triggering animation callbacks. */
217+ public boolean hideNow () {
216218 return setVisible (/*visible=*/ false , /*restart=*/ false , /*animationDesired=*/ false );
217219 }
218220
221+ @ Override
222+ public boolean setVisible (boolean visible , boolean restart ) {
223+ return setVisible (visible , restart , /*animationDesired=*/ true );
224+ }
225+
219226 /**
220- * Sets the visibility with/without animation based on system animator duration scale .
227+ * Changes the visibility with/without triggering the animation callbacks .
221228 *
229+ * @param visible Whether to make the drawable visible.
230+ * @param restart Whether to force starting the animation from the beginning.
231+ * @param animationDesired Whether to change the visibility with animation.
232+ * @return {@code true}, if the visibility changes or will change after the animation; {@code
233+ * false}, otherwise.
222234 * @see #setVisible(boolean, boolean, boolean)
223235 */
224- @ Override
225- public boolean setVisible (boolean visible , boolean restart ) {
236+ public boolean setVisible (boolean visible , boolean restart , boolean animationDesired ) {
226237 float systemAnimatorDurationScale =
227238 animatorDurationScaleProvider .getSystemAnimatorDurationScale (context .getContentResolver ());
228239 // Only show/hide the drawable with animations if system animator duration scale is not off and
229240 // some grow mode is used.
230- return setVisible (visible , restart , systemAnimatorDurationScale > 0 );
241+ return setVisibleInternal (
242+ visible , restart , animationDesired && systemAnimatorDurationScale > 0 );
231243 }
232244
233245 /**
234- * Show or hide the drawable with/without animation effects.
246+ * Show or hide the drawable with/without animation effects and/or animation callbacks .
235247 *
236248 * @param visible Whether to make the drawable visible.
237249 * @param restart Whether to force starting the animation from the beginning.
238250 * @param animationDesired Whether to change the visibility with animation.
239251 * @return {@code true}, if the visibility changes or will change after the animation; {@code
240252 * false}, otherwise.
241253 */
242- public boolean setVisible (boolean visible , boolean restart , boolean animationDesired ) {
254+ protected boolean setVisibleInternal (boolean visible , boolean restart , boolean animationDesired ) {
255+ maybeInitializeAnimators ();
243256 if (!isVisible () && !visible ) {
244- // Early return if trying to hide a hidden drawable.
257+ // Early returns if trying to hide a hidden drawable.
245258 return false ;
246259 }
247260
248- maybeInitializeAnimators () ;
261+ ValueAnimator animatorInAction = visible ? showAnimator : hideAnimator ;
249262
250- if (animationDesired && (visible ? showAnimator : hideAnimator ).isRunning ()) {
251- // Show/hide animation should not be reset while being played.
252- return false ;
263+ if (!animationDesired ) {
264+ if (animatorInAction .isRunning ()) {
265+ // Show/hide animation should fast-forward to the end without callbacks.
266+ endAnimatorWithoutCallbacks (animatorInAction );
267+ }
268+ // Immediately updates the drawable's visibility without animation if not desired.
269+ return super .setVisible (visible , DEFAULT_DRAWABLE_RESTART );
253270 }
254271
255- ValueAnimator animationInAction = visible ? showAnimator : hideAnimator ;
272+ if (animationDesired && animatorInAction .isRunning ()) {
273+ // Show/hide animation should not be replayed while playing.
274+ return false ;
275+ }
256276
257277 // If requests to show, sets the drawable visible. If requests to hide, the visibility is
258278 // controlled by the animation listener attached to hide animation.
@@ -262,19 +282,28 @@ public boolean setVisible(boolean visible, boolean restart, boolean animationDes
262282 if (!animationDesired ) {
263283 // This triggers onAnimationStart() callbacks for showing and onAnimationEnd() callbacks for
264284 // hiding. It also fast-forwards the animator properties to the end state.
265- animationInAction .end ();
285+ animatorInAction .end ();
266286 return changed ;
267287 }
268288
269- if (restart || VERSION .SDK_INT < 19 || !animationInAction .isPaused ()) {
289+ if (restart || VERSION .SDK_INT < 19 || !animatorInAction .isPaused ()) {
270290 // Starts/restarts the animator if requested or not eligible to resume.
271- animationInAction .start ();
291+ animatorInAction .start ();
272292 } else {
273- animationInAction .resume ();
293+ animatorInAction .resume ();
274294 }
275295 return changed ;
276296 }
277297
298+ private void endAnimatorWithoutCallbacks (@ NonNull ValueAnimator ... animators ) {
299+ boolean ignoreCallbacksOrig = ignoreCallbacks ;
300+ ignoreCallbacks = true ;
301+ for (ValueAnimator animator : animators ) {
302+ animator .end ();
303+ }
304+ ignoreCallbacks = ignoreCallbacksOrig ;
305+ }
306+
278307 // ******************* Getters and setters *******************
279308
280309 @ Override
0 commit comments