diff --git a/catalog/java/io/material/catalog/slider/SliderFragment.java b/catalog/java/io/material/catalog/slider/SliderFragment.java
index 1e170deec5e..e9b6c2dd609 100644
--- a/catalog/java/io/material/catalog/slider/SliderFragment.java
+++ b/catalog/java/io/material/catalog/slider/SliderFragment.java
@@ -77,6 +77,13 @@ public Fragment createFragment() {
return new SliderScrollContainerDemoFragment();
}
});
+ additionalDemos.add(
+ new Demo(R.string.cat_slider_demo_label_behavior_title) {
+ @Override
+ public Fragment createFragment() {
+ return new SliderLabelBehaviorDemoFragment();
+ }
+ });
return additionalDemos;
}
diff --git a/catalog/java/io/material/catalog/slider/SliderLabelBehaviorDemoFragment.java b/catalog/java/io/material/catalog/slider/SliderLabelBehaviorDemoFragment.java
new file mode 100644
index 00000000000..c5f48e48539
--- /dev/null
+++ b/catalog/java/io/material/catalog/slider/SliderLabelBehaviorDemoFragment.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.material.catalog.slider;
+
+import io.material.catalog.R;
+
+import android.os.Bundle;
+import androidx.appcompat.widget.SwitchCompat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import com.google.android.material.slider.RangeSlider;
+import com.google.android.material.slider.Slider;
+import io.material.catalog.feature.DemoFragment;
+
+/**
+ * Fragment to display a few basic uses of the {@link Slider} widget with different label behaviors
+ * for the Catalog app.
+ */
+public class SliderLabelBehaviorDemoFragment extends DemoFragment {
+
+ @Nullable
+ @Override
+ public View onCreateDemoView(
+ @NonNull LayoutInflater inflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle) {
+ View view =
+ inflater.inflate(
+ R.layout.cat_slider_demo_label_behavior, viewGroup, false /* attachToRoot */);
+
+ setUpSlider(view, R.id.switch_button_1, R.id.slider_1);
+ setUpSlider(view, R.id.switch_button_2, R.id.slider_2);
+ setUpSlider(view, R.id.switch_button_3, R.id.slider_3);
+ setUpSlider(view, R.id.switch_button_4, R.id.slider_4);
+
+ return view;
+ }
+
+ private void setUpSlider(
+ View view, @IdRes int switchId, @IdRes int sliderId) {
+ final RangeSlider slider = view.findViewById(sliderId);
+ SwitchCompat switchButton = view.findViewById(switchId);
+ switchButton.setOnCheckedChangeListener(
+ (buttonView, isChecked) -> slider.setEnabled(isChecked));
+ switchButton.setChecked(true);
+ }
+}
diff --git a/catalog/java/io/material/catalog/slider/res/layout/cat_slider_demo_label_behavior.xml b/catalog/java/io/material/catalog/slider/res/layout/cat_slider_demo_label_behavior.xml
new file mode 100644
index 00000000000..de7ed37d4f4
--- /dev/null
+++ b/catalog/java/io/material/catalog/slider/res/layout/cat_slider_demo_label_behavior.xml
@@ -0,0 +1,146 @@
+
+
+
Note that the custom drawables provided will be resized to match the thumb radius set by * {@link #setThumbRadius(int)} or {@link #setThumbRadiusResource(int)}. Be aware that the image @@ -857,9 +862,9 @@ void setCustomThumbDrawablesForValues(@NonNull @DrawableRes int... customThumbDr /** * Sets custom thumb drawables. The drawables provided will be used in its corresponding value - * position - i.e., the first drawable will be used to indicate the first value, and so on. If - * the number of drawables is less than the number of values, the default drawable will be used - * for the remaining values. + * position - i.e., the first drawable will be used to indicate the first value, and so on. If the + * number of drawables is less than the number of values, the default drawable will be used for + * the remaining values. * *
Note that the custom drawables provided will be resized to match the thumb radius set by
* {@link #setThumbRadius(int)} or {@link #setThumbRadiusResource(int)}. Be aware that the image
@@ -889,7 +894,7 @@ private void adjustCustomThumbDrawableBounds(Drawable drawable) {
if (originalWidth == -1 && originalHeight == -1) {
drawable.setBounds(0, 0, thumbDiameter, thumbDiameter);
} else {
- float scaleRatio = (float) thumbDiameter / Math.max(originalWidth, originalHeight);
+ float scaleRatio = (float) thumbDiameter / max(originalWidth, originalHeight);
drawable.setBounds(
0, 0, (int) (originalWidth * scaleRatio), (int) (originalHeight * scaleRatio));
}
@@ -920,8 +925,8 @@ public int getActiveThumbIndex() {
}
/**
- * Registers a callback to be invoked when the slider changes.
- * On the RangeSlider implementation, the listener is invoked once for each value.
+ * Registers a callback to be invoked when the slider changes. On the RangeSlider implementation,
+ * the listener is invoked once for each value.
*
* @param listener The callback to run when the slider changes
*/
@@ -1017,9 +1022,9 @@ public void setThumbElevationResource(@DimenRes int elevation) {
/**
* Returns the radius of the thumb. Note that setting this will also affect custom drawables set
- * through {@link #setCustomThumbDrawable(int)}, {@link #setCustomThumbDrawable(Drawable)},
- * {@link #setCustomThumbDrawablesForValues(int...)}, and
- * {@link #setCustomThumbDrawablesForValues(Drawable...)}.
+ * through {@link #setCustomThumbDrawable(int)}, {@link #setCustomThumbDrawable(Drawable)}, {@link
+ * #setCustomThumbDrawablesForValues(int...)}, and {@link
+ * #setCustomThumbDrawablesForValues(Drawable...)}.
*
* @see #setThumbRadius(int)
* @see #setThumbRadiusResource(int)
@@ -1032,9 +1037,9 @@ public int getThumbRadius() {
/**
* Sets the radius of the thumb in pixels. Note that setting this will also affect custom
- * drawables set through {@link #setCustomThumbDrawable(int)},
- * {@link #setCustomThumbDrawable(Drawable)}, {@link #setCustomThumbDrawablesForValues(int...)},
- * and {@link #setCustomThumbDrawablesForValues(Drawable...)}.
+ * drawables set through {@link #setCustomThumbDrawable(int)}, {@link
+ * #setCustomThumbDrawable(Drawable)}, {@link #setCustomThumbDrawablesForValues(int...)}, and
+ * {@link #setCustomThumbDrawablesForValues(Drawable...)}.
*
* @see #getThumbRadius()
* @attr ref com.google.android.material.R.styleable#Slider_thumbRadius
@@ -1063,9 +1068,9 @@ public void setThumbRadius(@IntRange(from = 0) @Dimension int radius) {
/**
* Sets the radius of the thumb from a dimension resource. Note that setting this will also affect
- * custom drawables set through {@link #setCustomThumbDrawable(int)},
- * {@link #setCustomThumbDrawable(Drawable)}, {@link #setCustomThumbDrawablesForValues(int...)},
- * and {@link #setCustomThumbDrawablesForValues(Drawable...)}.
+ * custom drawables set through {@link #setCustomThumbDrawable(int)}, {@link
+ * #setCustomThumbDrawable(Drawable)}, {@link #setCustomThumbDrawablesForValues(int...)}, and
+ * {@link #setCustomThumbDrawablesForValues(Drawable...)}.
*
* @see #getThumbRadius()
* @attr ref com.google.android.material.R.styleable#Slider_thumbRadius
@@ -1225,6 +1230,16 @@ public void setLabelBehavior(@LabelBehavior int labelBehavior) {
}
}
+ /**
+ * Returns whether the labels should be always shown based on the {@link LabelBehavior}.
+ *
+ * @see LabelBehavior
+ * @attr ref com.google.android.material.R.styleable#Slider_labelBehavior
+ */
+ private boolean shouldAlwaysShowLabel() {
+ return this.labelBehavior == LABEL_VISIBLE;
+ }
+
/** Returns the side padding of the track. */
@Dimension()
public int getTrackSidePadding() {
@@ -1580,7 +1595,9 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
widthMeasureSpec,
MeasureSpec.makeMeasureSpec(
widgetHeight
- + (labelBehavior == LABEL_WITHIN_BOUNDS ? labels.get(0).getIntrinsicHeight() : 0),
+ + (labelBehavior == LABEL_WITHIN_BOUNDS || shouldAlwaysShowLabel()
+ ? labels.get(0).getIntrinsicHeight()
+ : 0),
MeasureSpec.EXACTLY));
}
@@ -1599,7 +1616,7 @@ private void maybeCalculateTicksCoordinates() {
int tickCount = (int) ((valueTo - valueFrom) / stepSize + 1);
// Limit the tickCount if they will be too dense.
- tickCount = Math.min(tickCount, trackWidth / (trackHeight * 2) + 1);
+ tickCount = min(tickCount, trackWidth / (trackHeight * 2) + 1);
if (ticksCoordinates == null || ticksCoordinates.length != tickCount * 2) {
ticksCoordinates = new float[tickCount * 2];
}
@@ -1613,7 +1630,7 @@ private void maybeCalculateTicksCoordinates() {
private void updateTrackWidth(int width) {
// Update the visible track width.
- trackWidth = Math.max(width - trackSidePadding * 2, 0);
+ trackWidth = max(width - trackSidePadding * 2, 0);
// Update the visible tick coordinates.
maybeCalculateTicksCoordinates();
@@ -1634,7 +1651,9 @@ private void updateHaloHotspot() {
private int calculateTop() {
return trackTop
- + (labelBehavior == LABEL_WITHIN_BOUNDS ? labels.get(0).getIntrinsicHeight() : 0);
+ + (labelBehavior == LABEL_WITHIN_BOUNDS || shouldAlwaysShowLabel()
+ ? labels.get(0).getIntrinsicHeight()
+ : 0);
}
@Override
@@ -1651,19 +1670,22 @@ protected void onDraw(@NonNull Canvas canvas) {
int top = calculateTop();
drawInactiveTrack(canvas, trackWidth, top);
- if (Collections.max(getValues()) > valueFrom) {
+ if (max(getValues()) > valueFrom) {
drawActiveTrack(canvas, trackWidth, top);
}
maybeDrawTicks(canvas);
- if ((thumbIsPressed || isFocused()) && isEnabled()) {
+ if ((thumbIsPressed || isFocused() || shouldAlwaysShowLabel()) && isEnabled()) {
maybeDrawHalo(canvas, trackWidth, top);
-
- // Draw labels if there is an active thumb.
- if (activeThumbIdx != -1) {
+ // Draw labels if there is an active thumb or the labels are always visible.
+ if (activeThumbIdx != -1 || shouldAlwaysShowLabel()) {
ensureLabelsAdded();
+ } else {
+ ensureLabelsRemoved();
}
+ } else {
+ ensureLabelsRemoved();
}
drawThumbs(canvas, trackWidth, top);
@@ -1674,8 +1696,8 @@ protected void onDraw(@NonNull Canvas canvas) {
* float[1]} is the normalized right position of the range.
*/
private float[] getActiveRange() {
- float max = Collections.max(getValues());
- float min = Collections.min(getValues());
+ float max = max(getValues());
+ float min = min(getValues());
float left = normalizeValue(values.size() == 1 ? valueFrom : min);
float right = normalizeValue(max);
@@ -1769,8 +1791,7 @@ private void drawThumbDrawable(
trackSidePadding
+ (int) (normalizeValue(value) * width)
- (thumbDrawable.getBounds().width() / 2f),
- top
- - (thumbDrawable.getBounds().height() / 2f));
+ top - (thumbDrawable.getBounds().height() / 2f));
thumbDrawable.draw(canvas);
canvas.restore();
}
@@ -1805,8 +1826,8 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
}
float x = event.getX();
touchPosition = (x - trackSidePadding) / trackWidth;
- touchPosition = Math.max(0, touchPosition);
- touchPosition = Math.min(1, touchPosition);
+ touchPosition = max(0, touchPosition);
+ touchPosition = min(1, touchPosition);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
@@ -1869,7 +1890,6 @@ && abs(lastEvent.getY() - event.getY()) <= scaledTouchSlop) {
activeThumbIdx = -1;
onStopTrackingTouch();
}
- ensureLabelsRemoved();
invalidate();
break;
default:
@@ -2299,7 +2319,6 @@ public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
activeThumbIdx = -1;
- ensureLabelsRemoved();
postInvalidate();
return true;
default:
@@ -2441,7 +2460,6 @@ protected void onFocusChanged(
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
if (!gainFocus) {
activeThumbIdx = -1;
- ensureLabelsRemoved();
accessibilityHelper.clearKeyboardFocusForVirtualView(focusedThumbIdx);
} else {
focusThumbOnFocusGained(direction);
@@ -2610,7 +2628,7 @@ void updateBoundsForVirturalViewId(int virtualViewId, Rect virtualViewBounds) {
private static class AccessibilityHelper extends ExploreByTouchHelper {
private final BaseSlider, ?, ?> slider;
- Rect virtualViewBounds = new Rect();
+ final Rect virtualViewBounds = new Rect();
AccessibilityHelper(BaseSlider, ?, ?> slider) {
super(slider);
diff --git a/lib/java/com/google/android/material/slider/LabelFormatter.java b/lib/java/com/google/android/material/slider/LabelFormatter.java
index 83a00bd3276..d108cdbe9d0 100644
--- a/lib/java/com/google/android/material/slider/LabelFormatter.java
+++ b/lib/java/com/google/android/material/slider/LabelFormatter.java
@@ -27,6 +27,7 @@ public interface LabelFormatter {
int LABEL_FLOATING = 0;
int LABEL_WITHIN_BOUNDS = 1;
int LABEL_GONE = 2;
+ int LABEL_VISIBLE = 3;
@NonNull
String getFormattedValue(float value);
diff --git a/lib/java/com/google/android/material/slider/res/values/attrs.xml b/lib/java/com/google/android/material/slider/res/values/attrs.xml
index 770cb5d6ecb..fc0e9005c33 100644
--- a/lib/java/com/google/android/material/slider/res/values/attrs.xml
+++ b/lib/java/com/google/android/material/slider/res/values/attrs.xml
@@ -32,8 +32,10 @@