Skip to content

Commit a7da96f

Browse files
rubensousadsn5ft
authored andcommitted
[Slider] Fixed behaviour when Slider is in a scrolling container
Resolves #833 GIT_ORIGIN_REV_ID=86b976f757fb8354ffe502c5acc32b6954890bb9 PiperOrigin-RevId: 286431744
1 parent 2084fd3 commit a7da96f

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

catalog/java/io/material/catalog/slider/SliderFragment.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ public Fragment createFragment() {
7070
return new SliderDiscreteDemoFragment();
7171
}
7272
});
73+
additionalDemos.add(
74+
new Demo(R.string.cat_slider_demo_scroll_container_title) {
75+
@Override
76+
public Fragment createFragment() {
77+
return new SliderScrollContainerDemoFragment();
78+
}
79+
});
7380
return additionalDemos;
7481
}
7582

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
* Copyright 2019 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.material.catalog.slider;
18+
19+
import io.material.catalog.R;
20+
21+
import android.os.Bundle;
22+
import androidx.annotation.Nullable;
23+
import android.view.LayoutInflater;
24+
import android.view.View;
25+
import android.view.ViewGroup;
26+
import android.widget.LinearLayout;
27+
import com.google.android.material.slider.Slider;
28+
import io.material.catalog.feature.DemoFragment;
29+
30+
/**
31+
* A fragment that displays a list of {@link Slider} inside a ScrollView to showcase how touch
32+
* events are handled.
33+
*/
34+
public class SliderScrollContainerDemoFragment extends DemoFragment {
35+
36+
@Override
37+
public View onCreateDemoView(
38+
LayoutInflater layoutInflater, @Nullable ViewGroup viewGroup, @Nullable Bundle bundle) {
39+
View view =
40+
layoutInflater.inflate(
41+
R.layout.cat_slider_demo_scroll, viewGroup, false /* attachToRoot */);
42+
LinearLayout sliderContainer = view.findViewById(R.id.sliderContainer);
43+
for (int i = 0; i < 50; i++) {
44+
sliderContainer.addView(
45+
new Slider(layoutInflater.getContext()),
46+
ViewGroup.LayoutParams.MATCH_PARENT,
47+
ViewGroup.LayoutParams.WRAP_CONTENT);
48+
}
49+
return view;
50+
}
51+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2019 The Android Open Source Project
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<ScrollView
18+
xmlns:android="http://schemas.android.com/apk/res/android"
19+
android:layout_width="match_parent"
20+
android:layout_height="match_parent">
21+
22+
<LinearLayout
23+
android:id="@+id/sliderContainer"
24+
android:layout_width="match_parent"
25+
android:layout_height="wrap_content"
26+
android:paddingLeft="16dp"
27+
android:paddingRight="16dp"
28+
android:orientation="vertical">
29+
30+
31+
</LinearLayout>
32+
</ScrollView>

catalog/java/io/material/catalog/slider/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<string name="cat_slider_title" description="Title for the screen that showcases demonstrative usages of the Slider widget">Slider</string>
1919
<string name="cat_slider_demo_continuous_title" description="Title for the continuous Slider widget demo">Continuous Slider demo</string>
2020
<string name="cat_slider_demo_discrete_title" description="Title for the discrete Slider widget demo">Discrete Slider demo</string>
21+
<string name="cat_slider_demo_scroll_container_title" description="Title for the Slider inside scrolling container demo">Slider in scrolling container demo</string>
2122

2223
<string name="cat_slider_description" description="Body text describing the Slider widget within the design system [CHAR LIMIT=NONE]">
2324
Sliders let users select from a range of values by moving the slider thumb.

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
import android.view.InflateException;
5353
import android.view.MotionEvent;
5454
import android.view.View;
55+
import android.view.ViewConfiguration;
56+
import android.view.ViewGroup;
57+
import android.view.ViewParent;
5558
import com.google.android.material.drawable.DrawableUtils;
5659
import com.google.android.material.internal.DescendantOffsetUtils;
5760
import com.google.android.material.internal.ThemeEnforcement;
@@ -179,6 +182,8 @@ public class Slider extends View {
179182

180183
@NonNull private TooltipDrawable label;
181184

185+
private final int scaledTouchSlop;
186+
182187
private int widgetHeight;
183188
private boolean floatingLabel;
184189
private int trackHeight;
@@ -187,6 +192,7 @@ public class Slider extends View {
187192
private int thumbRadius;
188193
private int haloRadius;
189194
private int labelPadding;
195+
private float touchDownX;
190196
private OnChangeListener listener;
191197
private LabelFormatter formatter;
192198
private boolean thumbIsPressed = false;
@@ -315,6 +321,8 @@ public void onFocusChange(View v, boolean hasFocus) {
315321

316322
// Set up the thumb drawable to always show the compat shadow.
317323
thumbDrawable.setShadowCompatibilityMode(MaterialShapeDrawable.SHADOW_COMPAT_MODE_ALWAYS);
324+
325+
scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
318326
}
319327

320328
private void loadResources(@NonNull Resources resources) {
@@ -924,6 +932,12 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
924932

925933
switch (event.getActionMasked()) {
926934
case MotionEvent.ACTION_DOWN:
935+
// If we're inside a scrolling container,
936+
// we should start dragging in ACTION_MOVE
937+
if (isInScrollingContainer()) {
938+
touchDownX = event.getX();
939+
break;
940+
}
927941
getParent().requestDisallowInterceptTouchEvent(true);
928942
requestFocus();
929943
thumbIsPressed = true;
@@ -938,6 +952,14 @@ public boolean onTouchEvent(@NonNull MotionEvent event) {
938952
}
939953
break;
940954
case MotionEvent.ACTION_MOVE:
955+
if (!thumbIsPressed) {
956+
// Check if we're trying to scroll instead of dragging this Slider
957+
if (Math.abs(x - touchDownX) < scaledTouchSlop) {
958+
return false;
959+
}
960+
getParent().requestDisallowInterceptTouchEvent(true);
961+
}
962+
thumbIsPressed = true;
941963
thumbPosition = position;
942964
snapThumbPosition();
943965
updateHaloHotSpot();
@@ -1008,6 +1030,24 @@ private void invalidateTrack() {
10081030
activeTicksPaint.setStrokeWidth(trackHeight / 2.0f);
10091031
}
10101032

1033+
/**
1034+
* If this returns true, we can't start dragging the Slider immediately when we receive a {@link
1035+
* MotionEvent#ACTION_DOWN}. Instead, we must wait for a {@link MotionEvent#ACTION_MOVE}. Copied
1036+
* from hidden method of {@link View} isInScrollingContainer.
1037+
*
1038+
* @return true if any of this View's parents is a scrolling View.
1039+
*/
1040+
private boolean isInScrollingContainer() {
1041+
ViewParent p = getParent();
1042+
while (p instanceof ViewGroup) {
1043+
if (((ViewGroup) p).shouldDelayChildPressedState()) {
1044+
return true;
1045+
}
1046+
p = p.getParent();
1047+
}
1048+
return false;
1049+
}
1050+
10111051
@Override
10121052
protected void drawableStateChanged() {
10131053
super.drawableStateChanged();

0 commit comments

Comments
 (0)