Skip to content

Commit 6e0c04b

Browse files
committed
[Slider] Add new tick visibility modes
1 parent 6e6c53a commit 6e0c04b

File tree

5 files changed

+165
-24
lines changed

5 files changed

+165
-24
lines changed

catalog/java/io/material/catalog/slider/res/layout/cat_slider_demo_discrete.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@
163163
android:valueFrom="0"
164164
android:valueTo="10"
165165
android:stepSize="1"
166-
app:tickVisible="false"/>
166+
app:tickVisibilityMode="hidden" />
167167
</LinearLayout>
168168

169169
<com.google.android.material.materialswitch.MaterialSwitch

docs/components/Slider.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -333,17 +333,20 @@ Element | Attribute | Related method(s)
333333

334334
#### Tick mark attributes
335335

336-
Element | Attribute | Related method(s) | Default value
337-
----------------------------------- | ----------------------- | ------------------------------------------------------- | -------------
338-
**Color** | `app:tickColor` | `setTickTintList`<br/>`getTickTintList` | `null`
339-
**Color for track's active part** | `app:tickColorActive` | `setTickActiveTintList`<br/>`getTickActiveTintList` | `?attr/colorSurfaceVariant`
340-
**Color for track's inactive part** | `app:tickColorInactive` | `setTickInactiveTintList`<br/>`getTickInactiveTintList` | `?attr/colorPrimary`
341-
**Tick visible** | `app:tickVisible` | `setTickVisible`<br/>`isTickVisible()` | `true`
336+
Element | Attribute | Related method(s) | Default value
337+
----------------------------------- | ------------------------ | ------------------------------------------------------- | -------------
338+
**Color** | `app:tickColor` | `setTickTintList`<br/>`getTickTintList` | `null`
339+
**Color for track's active part** | `app:tickColorActive` | `setTickActiveTintList`<br/>`getTickActiveTintList` | `?attr/colorSurfaceVariant`
340+
**Color for track's inactive part** | `app:tickColorInactive` | `setTickInactiveTintList`<br/>`getTickInactiveTintList` | `?attr/colorPrimary`
341+
**Tick visible** (deprecated) | `app:tickVisible` | `setTickVisible`<br/>`isTickVisible()` | `true`
342+
**Tick visibility mode** | `app:tickVisibilityMode` | `setTickVisibilityMode`<br/>`getTickVisibilityMode()` | `autoLimit`
342343

343344
**Note:** `app:tickColor` takes precedence over `app:tickColorActive` and
344-
`app:tickColorInative`. It's a shorthand for setting both values to the same
345+
`app:tickColorInactive`. It's a shorthand for setting both values to the same
345346
thing.
346347

348+
**Note:** `app:tickVisible` is deprecated in favor of `app:tickVisibilityMode`.
349+
347350
#### Styles
348351

349352
Element | Style

lib/java/com/google/android/material/slider/BaseSlider.java

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
import static com.google.android.material.slider.LabelFormatter.LABEL_GONE;
2525
import static com.google.android.material.slider.LabelFormatter.LABEL_VISIBLE;
2626
import static com.google.android.material.slider.LabelFormatter.LABEL_WITHIN_BOUNDS;
27+
import static com.google.android.material.slider.TickVisibilityMode.TICK_VISIBILITY_AUTO_HIDE;
28+
import static com.google.android.material.slider.TickVisibilityMode.TICK_VISIBILITY_AUTO_LIMIT;
29+
import static com.google.android.material.slider.TickVisibilityMode.TICK_VISIBILITY_HIDDEN;
30+
import static com.google.android.material.slider.TickVisibilityMode.TICK_VISIBILITY_VISIBLE_ALL;
2731
import static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;
2832
import static java.lang.Float.compare;
2933
import static java.lang.Math.abs;
@@ -301,7 +305,7 @@ private interface TooltipDrawableFactory {
301305
private int focusedThumbIdx = -1;
302306
private float stepSize = 0.0f;
303307
private float[] ticksCoordinates;
304-
private boolean tickVisible = true;
308+
private int tickVisibilityMode;
305309
private int trackWidth;
306310
private boolean forceDrawCompatHalo;
307311
private boolean isLongPress = false;
@@ -481,7 +485,10 @@ private void processAttributes(Context context, AttributeSet attrs, int defStyle
481485
? haloColor
482486
: AppCompatResources.getColorStateList(context, R.color.material_slider_halo_color));
483487

484-
tickVisible = a.getBoolean(R.styleable.Slider_tickVisible, true);
488+
tickVisibilityMode = a.hasValue(R.styleable.Slider_tickVisibilityMode)
489+
? a.getInt(R.styleable.Slider_tickVisibilityMode, -1)
490+
: convertToTickVisibilityMode(a.getBoolean(R.styleable.Slider_tickVisible, true));
491+
485492
boolean hasTickColor = a.hasValue(R.styleable.Slider_tickColor);
486493
int tickColorInactiveRes =
487494
hasTickColor ? R.styleable.Slider_tickColor : R.styleable.Slider_tickColorInactive;
@@ -1485,22 +1492,61 @@ public void setTickInactiveTintList(@NonNull ColorStateList tickColor) {
14851492
/**
14861493
* Returns whether the tick marks are visible. Only used when the slider is in discrete mode.
14871494
*
1488-
* @see #setTickVisible(boolean)
14891495
* @attr ref com.google.android.material.R.styleable#Slider_tickVisible
14901496
*/
14911497
public boolean isTickVisible() {
1492-
return tickVisible;
1498+
switch (tickVisibilityMode) {
1499+
case TICK_VISIBILITY_VISIBLE_ALL:
1500+
case TICK_VISIBILITY_AUTO_LIMIT:
1501+
return true;
1502+
case TICK_VISIBILITY_AUTO_HIDE:
1503+
return getDesiredTickCount() <= getMaxTickCount();
1504+
case TICK_VISIBILITY_HIDDEN:
1505+
return false;
1506+
default:
1507+
throw new RuntimeException("isTickVisible() is not implemented for tickVisibilityMode=" + tickVisibilityMode);
1508+
}
14931509
}
14941510

14951511
/**
14961512
* Sets whether the tick marks are visible. Only used when the slider is in discrete mode.
14971513
*
14981514
* @param tickVisible The visibility of tick marks.
14991515
* @attr ref com.google.android.material.R.styleable#Slider_tickVisible
1516+
* @deprecated Use {@link #setTickVisibilityMode(int)} instead.
15001517
*/
1518+
@Deprecated
15011519
public void setTickVisible(boolean tickVisible) {
1502-
if (this.tickVisible != tickVisible) {
1503-
this.tickVisible = tickVisible;
1520+
setTickVisibilityMode(convertToTickVisibilityMode(tickVisible));
1521+
}
1522+
1523+
@TickVisibilityMode
1524+
private int convertToTickVisibilityMode(boolean tickVisible) {
1525+
return tickVisible
1526+
? TICK_VISIBILITY_AUTO_LIMIT
1527+
: TICK_VISIBILITY_HIDDEN;
1528+
}
1529+
1530+
/**
1531+
* Returns the current tick visibility mode.
1532+
*
1533+
* @see #setTickVisibilityMode(int)
1534+
* @attr ref com.google.android.material.R.styleable#Slider_tickVisibilityMode
1535+
*/
1536+
@TickVisibilityMode
1537+
public int getTickVisibilityMode() {
1538+
return tickVisibilityMode;
1539+
}
1540+
1541+
/**
1542+
* Sets the tick visibility mode. Only used when the slider is in discrete mode.
1543+
*
1544+
* @see #getTickVisibilityMode()
1545+
* @attr ref com.google.android.material.R.styleable#Slider_tickVisibilityMode
1546+
*/
1547+
public void setTickVisibilityMode(@TickVisibilityMode int tickVisibilityMode) {
1548+
if (this.tickVisibilityMode != tickVisibilityMode) {
1549+
this.tickVisibilityMode = tickVisibilityMode;
15041550
postInvalidate();
15051551
}
15061552
}
@@ -1675,24 +1721,58 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
16751721
updateHaloHotspot();
16761722
}
16771723

1678-
private void maybeCalculateTicksCoordinates() {
1724+
private void updateTicksCoordinates() {
16791725
if (stepSize <= 0.0f) {
1726+
updateTicksCoordinates(/* tickCount= */ 0);
16801727
return;
16811728
}
16821729

1683-
validateConfigurationIfDirty();
1730+
final int tickCount;
1731+
switch (tickVisibilityMode) {
1732+
case TICK_VISIBILITY_VISIBLE_ALL:
1733+
tickCount = getDesiredTickCount();
1734+
break;
1735+
case TICK_VISIBILITY_AUTO_LIMIT:
1736+
tickCount = min(getDesiredTickCount(), getMaxTickCount());
1737+
break;
1738+
case TICK_VISIBILITY_AUTO_HIDE:
1739+
int desiredTickCount = getDesiredTickCount();
1740+
tickCount = desiredTickCount <= getMaxTickCount() ? desiredTickCount : 0;
1741+
break;
1742+
case TICK_VISIBILITY_HIDDEN:
1743+
tickCount = 0;
1744+
break;
1745+
default:
1746+
throw new RuntimeException("Calculation of tick coordinates is not implemented for tickVisibilityMode=" + tickVisibilityMode);
1747+
}
1748+
1749+
updateTicksCoordinates(tickCount);
1750+
}
1751+
1752+
private int getDesiredTickCount() {
1753+
return (int) ((valueTo - valueFrom) / stepSize + 1);
1754+
}
1755+
1756+
private int getMaxTickCount() {
1757+
return trackWidth / (trackHeight * 2) + 1;
1758+
}
1759+
1760+
private void updateTicksCoordinates(int tickCount) {
1761+
if (tickCount == 0) {
1762+
ticksCoordinates = null;
1763+
return;
1764+
}
16841765

1685-
int tickCount = (int) ((valueTo - valueFrom) / stepSize + 1);
1686-
// Limit the tickCount if they will be too dense.
1687-
tickCount = min(tickCount, trackWidth / (trackHeight * 2) + 1);
16881766
if (ticksCoordinates == null || ticksCoordinates.length != tickCount * 2) {
16891767
ticksCoordinates = new float[tickCount * 2];
16901768
}
16911769

16921770
float interval = trackWidth / (float) (tickCount - 1);
1771+
float trackCenterY = calculateTrackCenter();
1772+
16931773
for (int i = 0; i < tickCount * 2; i += 2) {
16941774
ticksCoordinates[i] = trackSidePadding + i / 2 * interval;
1695-
ticksCoordinates[i + 1] = calculateTrackCenter();
1775+
ticksCoordinates[i + 1] = trackCenterY;
16961776
}
16971777
}
16981778

@@ -1701,7 +1781,7 @@ private void updateTrackWidth(int width) {
17011781
trackWidth = max(width - trackSidePadding * 2, 0);
17021782

17031783
// Update the visible tick coordinates.
1704-
maybeCalculateTicksCoordinates();
1784+
updateTicksCoordinates();
17051785
}
17061786

17071787
private void updateHaloHotspot() {
@@ -1730,7 +1810,7 @@ protected void onDraw(@NonNull Canvas canvas) {
17301810
validateConfigurationIfDirty();
17311811

17321812
// Update the visible tick coordinates.
1733-
maybeCalculateTicksCoordinates();
1813+
updateTicksCoordinates();
17341814
}
17351815

17361816
super.onDraw(canvas);
@@ -1807,7 +1887,7 @@ private void drawActiveTrack(@NonNull Canvas canvas, int width, int yCenter) {
18071887
}
18081888

18091889
private void maybeDrawTicks(@NonNull Canvas canvas) {
1810-
if (!tickVisible || stepSize <= 0.0f) {
1890+
if (ticksCoordinates == null || ticksCoordinates.length == 0) {
18111891
return;
18121892
}
18131893

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.google.android.material.slider;
2+
3+
import androidx.annotation.IntDef;
4+
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
8+
/**
9+
* Mode to specify the visibility of tick marks.
10+
*/
11+
@IntDef({
12+
TickVisibilityMode.TICK_VISIBILITY_VISIBLE_ALL,
13+
TickVisibilityMode.TICK_VISIBILITY_AUTO_LIMIT,
14+
TickVisibilityMode.TICK_VISIBILITY_AUTO_HIDE,
15+
TickVisibilityMode.TICK_VISIBILITY_HIDDEN
16+
})
17+
@Retention(RetentionPolicy.SOURCE)
18+
public @interface TickVisibilityMode {
19+
20+
/**
21+
* All tick marks will be drawn, even if they are spaced too densely.
22+
*/
23+
int TICK_VISIBILITY_VISIBLE_ALL = 0;
24+
25+
/**
26+
* All tick marks will be drawn if they are not spaced too densely. Otherwise, the maximum
27+
* allowed number of tick marks will be drawn.
28+
* Note that in this case, the drawn ticks may not match the actual snap values.
29+
*/
30+
int TICK_VISIBILITY_AUTO_LIMIT = 1;
31+
32+
/**
33+
* All tick marks will be drawn if they are not spaced too densely. Otherwise, the tick marks
34+
* will not be drawn.
35+
*/
36+
int TICK_VISIBILITY_AUTO_HIDE = 2;
37+
38+
/**
39+
* Tick marks will not be drawn.
40+
*/
41+
int TICK_VISIBILITY_HIDDEN = 3;
42+
}

lib/java/com/google/android/material/slider/res/values/attrs.xml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,24 @@
5959
<!-- The color of the slider's tick marks for the inactive portion of the track. Only used when
6060
the slider is in discrete mode. -->
6161
<attr name="tickColorInactive" format="color" />
62-
<!-- Whether to show the tick marks. Only used when the slider is in discrete mode. -->
62+
<!-- Whether to show the tick marks. Only used when the slider is in discrete mode.
63+
{@deprecated Use tickVisibilityMode instead.} -->
6364
<attr name="tickVisible" format="boolean" />
65+
<!-- Mode to specify the visibility of tick marks. Only used when the slider is in
66+
discrete mode. -->
67+
<attr name="tickVisibilityMode" format="enum">
68+
<!-- All tick marks will be drawn, even if they are spaced too densely. -->
69+
<enum name="visibleAll" value="0" />
70+
<!-- All tick marks will be drawn if they are not spaced too densely. Otherwise,
71+
the maximum allowed number of tick marks will be drawn.
72+
Note that in this case, the drawn ticks may not match the actual snap values. -->
73+
<enum name="autoLimit" value="1" />
74+
<!-- All tick marks will be drawn if they are not spaced too densely. Otherwise,
75+
the tick marks will not be drawn. -->
76+
<enum name="autoHide" value="2" />
77+
<!-- Tick marks will not be drawn. -->
78+
<enum name="hidden" value="3" />
79+
</attr>
6480
<!-- The color of the track. -->
6581
<attr name="trackColor" />
6682
<!-- The color of active portion of the track. -->

0 commit comments

Comments
 (0)