1

So I have a "both" Slider which controls "width" Slider and "length" Slider, like below:

<com.google.android.material.slider.Slider
    android:id="@+id/width_slider"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:value="40"
    android:valueFrom="0"        <-
    android:valueTo="200"        <-
    android:stepSize="1"/>       <-

<com.google.android.material.slider.Slider
    android:id="@+id/height_slider"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:value="40"
    android:valueFrom="0"        <-
    android:valueTo="200"        <-
    android:stepSize="1"/>       <-

<com.google.android.material.slider.Slider
    android:id="@+id/both_slider"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:value="100"   
    android:valueFrom="0"        <-
    android:valueTo="200"        <-
    android:stepSize="1"/>       <-

As I marked above, they all have same range (from & to) and the stepSize to 1 (important), and I set the behavior of

when adding/subtracting value 1 on the both Slider, the other two will be added/subtracted value 1 too.

Code as below:

private var previousValue = 50f        //initial value, same as on xml

binding.bothSlider.addOnChangeListener { slider, value, fromUser ->
    if (value > previousValue) {
        binding.widthSlider.value++
        binding.heightSlider.value++
    }

    if (value < previousValue) {
        binding.widthSlider.value--
        binding.heightSlider.value--
    }

    previousValue = value
}

And weird thing happens, it seems like the width and height Slider has some a bit slow reaction (I guess), and skip some point:

enter image description here

They should be synchronized, because they have same stepSize and value range (just the initial values are different). Any help would be appreciated.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
Sam Chen
  • 7,597
  • 2
  • 40
  • 73
  • Probably your listener is called less frequently than you think. That is, if the slider is at 50 and you drag it to 70 very quickly, it is probably called ~3 times, not 20 times. – Ben P. Jan 16 '21 at 22:38
  • @Ben P. If so, what's the solution? – Sam Chen Jan 16 '21 at 22:46

2 Answers2

4

Use the current value of the "both" slider to set the values of the others.

binding.bothSlider.addOnChangeListener { _, value, _->
    binding.widthSlider.value = value
    binding.heightSlider.value = value
}

It's a little hard to know exactly what you're trying to do. You could also do something similar to what you have but use a diff instead of just 1:

binding.bothSlider.addOnChangeListener { slider, value, fromUser ->
    val diff = value - previousValue
    binding.widthSlider.value += diff
    binding.heightSlider.value += diff

    previousValue = value
}

This will let the sliders diverge but will still solve the "speed" problem you're having.

Ben P.
  • 52,661
  • 6
  • 95
  • 123
  • This is a whole lot more elegant, but the issue with the initial offset would persist. – Martin Zeitler Jan 18 '21 at 00:08
  • Thank you for the solution, I just found out that my `previousValue` didn't match the xml initial value...such a stupid mistake, sorry for that. – Sam Chen Jan 19 '21 at 03:59
2

Those sliders seem to have a different scale...

but actually it's the initial value which creates an offset of 60:

<com.google.android.material.slider.Slider
    android:id="@+id/both_slider"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:value="40" <-- 100 != 40
    android:valueFrom="0"
    android:valueTo="200"
    android:stepSize="1"/> 
Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • Thank you for the solution, I just found out that my `previousValue` didn't match the xml initial value (100) ...such a stupid mistake, sorry for that. – Sam Chen Jan 19 '21 at 03:59