From 868f1c6afed7e92b4d7a6a117a31f476f5d0f676 Mon Sep 17 00:00:00 2001 From: pubiqq Date: Fri, 10 Jan 2025 19:24:23 +0300 Subject: [PATCH] [Slider] Fix slider height and side padding --- .../android/material/math/MathUtils.java | 45 ++++++++++++++++ .../android/material/slider/BaseSlider.java | 53 ++++++++++++------- 2 files changed, 80 insertions(+), 18 deletions(-) diff --git a/lib/java/com/google/android/material/math/MathUtils.java b/lib/java/com/google/android/material/math/MathUtils.java index b09c88f8855..2603482a3f0 100644 --- a/lib/java/com/google/android/material/math/MathUtils.java +++ b/lib/java/com/google/android/material/math/MathUtils.java @@ -16,6 +16,9 @@ package com.google.android.material.math; import androidx.annotation.NonNull; +import androidx.annotation.RestrictTo; + +import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP; /** A class that contains utility methods related to numbers. */ public final class MathUtils { @@ -102,6 +105,48 @@ public static int floorMod(int x, int y) { return x - r * y; } + /** + * The same as {@link Math#ceilDiv(int, int)}, but for API < 35. + * + * @hide + */ + @RestrictTo(LIBRARY_GROUP) + public static int ceilDiv(int x, int y) { + final int q = x / y; + // if the signs are the same and modulo not zero, round up + if ((x ^ y) >= 0 && (q * y != x)) { + return q + 1; + } + return q; + } + + /** + * Returns the greater of the given values. + * + * @hide + */ + @RestrictTo(LIBRARY_GROUP) + public static int max(final int... array) { + validateArray(array); + + int max = array[0]; + for (int i = 1; i < array.length; i++) { + if (array[i] > max) { + max = array[i]; + } + } + return max; + } + + private static void validateArray(final int[] array) { + if (array == null) { + throw new NullPointerException("The array should not be null"); + } + if (array.length == 0) { + throw new IllegalArgumentException("The array should not be empty"); + } + } + /** * Returns whether the array contains all same elements. * diff --git a/lib/java/com/google/android/material/slider/BaseSlider.java b/lib/java/com/google/android/material/slider/BaseSlider.java index f390a01f97a..5f795d6731e 100644 --- a/lib/java/com/google/android/material/slider/BaseSlider.java +++ b/lib/java/com/google/android/material/slider/BaseSlider.java @@ -102,6 +102,7 @@ import com.google.android.material.internal.DescendantOffsetUtils; import com.google.android.material.internal.ThemeEnforcement; import com.google.android.material.internal.ViewUtils; +import com.google.android.material.math.MathUtils; import com.google.android.material.motion.MotionUtils; import com.google.android.material.resources.MaterialResources; import com.google.android.material.shape.MaterialShapeDrawable; @@ -662,16 +663,21 @@ private void processAttributes(Context context, AttributeSet attrs, int defStyle a.recycle(); } - private boolean maybeIncreaseTrackSidePadding() { - int increasedSidePaddingByThumb = max(thumbWidth / 2 - defaultThumbRadius, 0); - int increasedSidePaddingByTrack = max((trackThickness - defaultTrackThickness) / 2, 0); - int increasedSidePaddingByActiveTick = max(tickActiveRadius - defaultTickActiveRadius, 0); - int increasedSidePaddingByInactiveTick = max(tickInactiveRadius - defaultTickInactiveRadius, 0); + private boolean isSidePaddingChanged() { + int minSideSpaceWidthForThumb = MathUtils.ceilDiv(thumbWidth, 2); + int minSideSpaceWidthForTrack = getTrackCornerSize(); + int minSideSpaceWidthForActiveTick = tickActiveRadius; + int minSideSpaceWidthForInactiveTick = tickInactiveRadius; + int minSideSpaceWidthForStopIndicator = MathUtils.ceilDiv(trackStopIndicatorSize, 2); + int newTrackSidePadding = - minTrackSidePadding - + max( - max(increasedSidePaddingByThumb, increasedSidePaddingByTrack), - max(increasedSidePaddingByActiveTick, increasedSidePaddingByInactiveTick)); + minTrackSidePadding + + MathUtils.max( + minSideSpaceWidthForThumb, + minSideSpaceWidthForTrack, + minSideSpaceWidthForActiveTick, + minSideSpaceWidthForInactiveTick, + minSideSpaceWidthForStopIndicator); if (trackSidePadding == newTrackSidePadding) { return false; @@ -1594,8 +1600,8 @@ public void setTickInactiveRadius(@IntRange(from = 0) @Px int tickInactiveRadius } private void updateWidgetLayout(boolean forceRefresh) { - boolean sizeChanged = maybeIncreaseWidgetThickness(); - boolean sidePaddingChanged = maybeIncreaseTrackSidePadding(); + boolean sizeChanged = isWidgetThicknessChanged(); + boolean sidePaddingChanged = isSidePaddingChanged(); if (isVertical()) { updateRotationMatrix(); } @@ -1606,22 +1612,33 @@ private void updateWidgetLayout(boolean forceRefresh) { } } - private boolean maybeIncreaseWidgetThickness() { + private boolean isWidgetThicknessChanged() { int paddings; if (isVertical()) { paddings = getPaddingLeft() + getPaddingRight(); } else { paddings = getPaddingTop() + getPaddingBottom(); } - int minHeightRequiredByTrack = trackThickness + paddings; - int minHeightRequiredByThumb = thumbHeight + paddings; - int newWidgetHeight = - max(minWidgetThickness, max(minHeightRequiredByTrack, minHeightRequiredByThumb)); - if (newWidgetHeight == widgetThickness) { + int minSpaceHeightForThumb = thumbHeight; + int minSpaceHeightForTrack = trackThickness; + int minSpaceHeightForActiveTick = tickActiveRadius * 2; + int minSpaceHeightForInactiveTick = tickInactiveRadius * 2; + int minSpaceHeightForStopIndicator = trackStopIndicatorSize; + + int newWidgetThickness = paddings + + MathUtils.max( + minSpaceHeightForThumb, + minSpaceHeightForTrack, + minSpaceHeightForActiveTick, + minSpaceHeightForInactiveTick, + minSpaceHeightForStopIndicator); + + newWidgetThickness = max(minWidgetThickness, newWidgetThickness); + if (newWidgetThickness == widgetThickness) { return false; } - widgetThickness = newWidgetHeight; + widgetThickness = newWidgetThickness; return true; }