Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.os.Looper;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import androidx.annotation.AttrRes;
Expand Down Expand Up @@ -185,6 +186,12 @@ public CornerSize apply(@NonNull CornerSize cornerSize) {
private boolean shadowBitmapDrawingEnable = true;

// Variables for corner morph.
// Tracks if this is the first non-empty bounds (for skipping initial animation).
private boolean boundsIsEmpty = true;
// Timestamp when state change occurred, used to allow animation during state transitions.
private long stateChangeTimestamp = 0;
// Duration (ms) to allow animation after state change, accounting for animation frames.
private static final long STATE_CHANGE_ANIMATION_WINDOW_MS = 500;
private boolean isRoundRectCornerMorph = true;
@NonNull private ShapeAppearanceModel strokeShapeAppearanceModel;
@Nullable private SpringForce cornerSpringForce;
Expand Down Expand Up @@ -1109,10 +1116,19 @@ protected void onBoundsChange(Rect bounds) {
pathDirty = true;
strokePathDirty = true;
super.onBoundsChange(bounds);

if (drawableState.shapeAppearance.isStateful() && !bounds.isEmpty()) {
// When bounds change, we want to snap to the new shape without animation.
updateShape(getState(), /* skipAnimation= */ true);
// Check if we're within the animation window after a state change.
long timeSinceStateChange = SystemClock.elapsedRealtime() - stateChangeTimestamp;
boolean isWithinStateChangeWindow = timeSinceStateChange < STATE_CHANGE_ANIMATION_WINDOW_MS;

// Skip animation if this is the first non-empty bounds OR outside state change window.
// Allow animation if we're within the window after a state change.
boolean skipAnimation = boundsIsEmpty || !isWithinStateChangeWindow;
updateShape(getState(), skipAnimation);
}

boundsIsEmpty = bounds.isEmpty();
}

@Override
Expand Down Expand Up @@ -1537,6 +1553,8 @@ public boolean isStateful() {
@Override
protected boolean onStateChange(int[] state) {
if (drawableState.shapeAppearance.isStateful()) {
// Record state change timestamp to allow animation within the time window.
stateChangeTimestamp = SystemClock.elapsedRealtime();
updateShape(state);
}
boolean paintColorChanged = updateColorsForState(state);
Expand Down