Skip to content

Commit 4a0b05d

Browse files
committed
[Slider] Add new tick visibility modes
1 parent b3acd17 commit 4a0b05d

File tree

5 files changed

+151
-30
lines changed

5 files changed

+151
-30
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: 81 additions & 21 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;
@@ -55,6 +59,8 @@
5559
import android.os.Bundle;
5660
import android.os.Parcel;
5761
import android.os.Parcelable;
62+
63+
import androidx.annotation.RestrictTo;
5864
import androidx.appcompat.content.res.AppCompatResources;
5965
import android.util.AttributeSet;
6066
import android.util.Log;
@@ -292,7 +298,8 @@ private interface TooltipDrawableFactory {
292298
private int focusedThumbIdx = -1;
293299
private float stepSize = 0.0f;
294300
private float[] ticksCoordinates;
295-
private boolean tickVisible = true;
301+
private boolean tickVisible = false;
302+
private int tickVisibilityMode;
296303
private int trackWidth;
297304
private boolean forceDrawCompatHalo;
298305
private boolean isLongPress = false;
@@ -472,7 +479,15 @@ private void processAttributes(Context context, AttributeSet attrs, int defStyle
472479
? haloColor
473480
: AppCompatResources.getColorStateList(context, R.color.material_slider_halo_color));
474481

475-
tickVisible = a.getBoolean(R.styleable.Slider_tickVisible, true);
482+
int tickVisibilityMode = a.getInt(R.styleable.Slider_tickVisibilityMode, -1);
483+
if (tickVisibilityMode != -1) {
484+
this.tickVisibilityMode = tickVisibilityMode;
485+
} else {
486+
this.tickVisibilityMode = a.getBoolean(R.styleable.Slider_tickVisible, true)
487+
? TICK_VISIBILITY_AUTO_LIMIT
488+
: TICK_VISIBILITY_HIDDEN;
489+
}
490+
476491
boolean hasTickColor = a.hasValue(R.styleable.Slider_tickColor);
477492
int tickColorInactiveRes =
478493
hasTickColor ? R.styleable.Slider_tickColor : R.styleable.Slider_tickColorInactive;
@@ -1474,10 +1489,7 @@ public void setTickInactiveTintList(@NonNull ColorStateList tickColor) {
14741489
}
14751490

14761491
/**
1477-
* Returns whether the tick marks are visible. Only used when the slider is in discrete mode.
1478-
*
1479-
* @see #setTickVisible(boolean)
1480-
* @attr ref com.google.android.material.R.styleable#Slider_tickVisible
1492+
* Returns whether the tick marks are visible.
14811493
*/
14821494
public boolean isTickVisible() {
14831495
return tickVisible;
@@ -1488,10 +1500,33 @@ public boolean isTickVisible() {
14881500
*
14891501
* @param tickVisible The visibility of tick marks.
14901502
* @attr ref com.google.android.material.R.styleable#Slider_tickVisible
1503+
* @deprecated Use {@link BaseSlider#setTickVisibilityMode(int)} instead.
14911504
*/
1505+
@Deprecated
14921506
public void setTickVisible(boolean tickVisible) {
1493-
if (this.tickVisible != tickVisible) {
1494-
this.tickVisible = tickVisible;
1507+
setTickVisibilityMode(tickVisible ? TICK_VISIBILITY_AUTO_LIMIT : TICK_VISIBILITY_HIDDEN);
1508+
}
1509+
1510+
/**
1511+
* Returns the current tick visibility mode.
1512+
*
1513+
* @see #setTickVisibilityMode(int)
1514+
* @attr ref com.google.android.material.R.styleable#Slider_tickVisibilityMode
1515+
*/
1516+
@TickVisibilityMode
1517+
public int getTickVisibilityMode() {
1518+
return tickVisibilityMode;
1519+
}
1520+
1521+
/**
1522+
* Sets the tick visibility mode. Only used when the slider is in discrete mode.
1523+
*
1524+
* @see #getTickVisibilityMode()
1525+
* @attr ref com.google.android.material.R.styleable#Slider_tickVisibilityMode
1526+
*/
1527+
public void setTickVisibilityMode(@TickVisibilityMode int tickVisibilityMode) {
1528+
if (this.tickVisibilityMode != tickVisibilityMode) {
1529+
this.tickVisibilityMode = tickVisibilityMode;
14951530
postInvalidate();
14961531
}
14971532
}
@@ -1666,24 +1701,47 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
16661701
updateHaloHotspot();
16671702
}
16681703

1669-
private void maybeCalculateTicksCoordinates() {
1670-
if (stepSize <= 0.0f) {
1704+
private void updateTicksCoordinates() {
1705+
if (stepSize <= 0.0f || tickVisibilityMode == TICK_VISIBILITY_HIDDEN) {
1706+
updateTicksCoordinates(0);
16711707
return;
16721708
}
16731709

1674-
validateConfigurationIfDirty();
1710+
final int tickCount = (int) ((valueTo - valueFrom) / stepSize + 1);
1711+
if (tickVisibilityMode == TICK_VISIBILITY_VISIBLE_ALL) {
1712+
updateTicksCoordinates(tickCount);
1713+
return;
1714+
}
1715+
1716+
final int maxTickCount = trackWidth / (trackHeight * 2) + 1;
1717+
switch (tickVisibilityMode) {
1718+
case TICK_VISIBILITY_AUTO_LIMIT:
1719+
updateTicksCoordinates(min(tickCount, maxTickCount));
1720+
return;
1721+
case TICK_VISIBILITY_AUTO_HIDE:
1722+
updateTicksCoordinates(tickCount <= maxTickCount ? tickCount : 0);
1723+
return;
1724+
default:
1725+
throw new IllegalArgumentException("Invalid tick visibility mode: " + tickVisibilityMode);
1726+
}
1727+
}
1728+
1729+
private void updateTicksCoordinates(int tickCount) {
1730+
if (tickCount == 0) {
1731+
ticksCoordinates = null;
1732+
return;
1733+
}
16751734

1676-
int tickCount = (int) ((valueTo - valueFrom) / stepSize + 1);
1677-
// Limit the tickCount if they will be too dense.
1678-
tickCount = min(tickCount, trackWidth / (trackHeight * 2) + 1);
16791735
if (ticksCoordinates == null || ticksCoordinates.length != tickCount * 2) {
16801736
ticksCoordinates = new float[tickCount * 2];
16811737
}
16821738

16831739
float interval = trackWidth / (float) (tickCount - 1);
1740+
float trackCenterY = calculateTrackCenter();
1741+
16841742
for (int i = 0; i < tickCount * 2; i += 2) {
16851743
ticksCoordinates[i] = trackSidePadding + i / 2 * interval;
1686-
ticksCoordinates[i + 1] = calculateTrackCenter();
1744+
ticksCoordinates[i + 1] = trackCenterY;
16871745
}
16881746
}
16891747

@@ -1692,7 +1750,7 @@ private void updateTrackWidth(int width) {
16921750
trackWidth = max(width - trackSidePadding * 2, 0);
16931751

16941752
// Update the visible tick coordinates.
1695-
maybeCalculateTicksCoordinates();
1753+
updateTicksCoordinates();
16961754
}
16971755

16981756
private void updateHaloHotspot() {
@@ -1721,7 +1779,7 @@ protected void onDraw(@NonNull Canvas canvas) {
17211779
validateConfigurationIfDirty();
17221780

17231781
// Update the visible tick coordinates.
1724-
maybeCalculateTicksCoordinates();
1782+
updateTicksCoordinates();
17251783
}
17261784

17271785
super.onDraw(canvas);
@@ -1733,7 +1791,7 @@ protected void onDraw(@NonNull Canvas canvas) {
17331791
drawActiveTrack(canvas, trackWidth, yCenter);
17341792
}
17351793

1736-
maybeDrawTicks(canvas);
1794+
tickVisible = maybeDrawTicks(canvas);
17371795

17381796
if ((thumbIsPressed || isFocused() || shouldAlwaysShowLabel()) && isEnabled()) {
17391797
maybeDrawHalo(canvas, trackWidth, yCenter);
@@ -1797,9 +1855,9 @@ private void drawActiveTrack(@NonNull Canvas canvas, int width, int yCenter) {
17971855
canvas.drawLine(left, yCenter, right, yCenter, activeTrackPaint);
17981856
}
17991857

1800-
private void maybeDrawTicks(@NonNull Canvas canvas) {
1801-
if (!tickVisible || stepSize <= 0.0f) {
1802-
return;
1858+
private boolean maybeDrawTicks(@NonNull Canvas canvas) {
1859+
if (ticksCoordinates == null || ticksCoordinates.length == 0) {
1860+
return false;
18031861
}
18041862

18051863
float[] activeRange = getActiveRange();
@@ -1822,6 +1880,8 @@ private void maybeDrawTicks(@NonNull Canvas canvas) {
18221880
rightPivotIndex * 2,
18231881
ticksCoordinates.length - rightPivotIndex * 2,
18241882
inactiveTicksPaint);
1883+
1884+
return true;
18251885
}
18261886

18271887
private void drawThumbs(@NonNull Canvas canvas, int width, int yCenter) {
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)