docs: @Override
      public boolean onTouchEvent(MotionEvent event) {
          if (!isEnabled())
              return false;
  
          float v = (value - min) / (max - min);
          float v2 = (value2 - min) / (max - min);
  
          if (event.getAction() == MotionEvent.ACTION_DOWN) {
              int thumbX = (int) (v * (getWidth() - getPaddingLeft() - getPaddingRight() - thumbRadius * 2) + getPaddingLeft() + thumbRadius);
              int thumbX2 = (int) (v2 * (getWidth() - getPaddingLeft() - getPaddingRight() - thumbRadius2 * 2) + getPaddingLeft() + thumbRadius2);
              if (Math.abs(event.getX() - thumbX) < Math.abs(event.getX() - thumbX2)) {
                  draggedThumb = 1;
                  if (radiusAnimator != null)
                      radiusAnimator.end();
                  radiusAnimator = ValueAnimator.ofFloat(thumbRadius, THUMB_RADIUS_DRAGGED);
                  radiusAnimator.setDuration(200);
                  radiusAnimator.setInterpolator(interpolator);
                  radiusAnimator.addUpdateListener(animation -> {
                      thumbRadius = (float) animation.getAnimatedValue();
                      postInvalidate();
                  });
                  radiusAnimator.addListener(new AnimatorListenerAdapter() {
                      @Override
                      public void onAnimationEnd(Animator animation) {
                          radiusAnimator = null;
                      }
                  });
                  radiusAnimator.start();
              } else {
                  draggedThumb = 2;
                  if (radiusAnimator != null)
                      radiusAnimator.end();
                  radiusAnimator = ValueAnimator.ofFloat(thumbRadius2, THUMB_RADIUS_DRAGGED);
                  radiusAnimator.setDuration(200);
                  radiusAnimator.setInterpolator(interpolator);
                  radiusAnimator.addUpdateListener(animation -> {
                      thumbRadius2 = (float) animation.getAnimatedValue();
                      postInvalidate();
                  });
                  radiusAnimator.addListener(new AnimatorListenerAdapter() {
                      @Override
                      public void onAnimationEnd(Animator animation) {
                          radiusAnimator = null;
                      }
                  });
                  radiusAnimator.start();
              }
              ViewParent parent = getParent();
              if (parent != null)
                  parent.requestDisallowInterceptTouchEvent(true);
              if (showLabel)
                  popup.show(this);
          } else if (event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_UP) {
              if (draggedThumb == 1) {
                  if (style == Style.Discrete) {
                      float val = (float) Math.floor((value - min + step / 2) / step) * step + min;
                      if (valueAnimator != null)
                          valueAnimator.cancel();
                      valueAnimator = ValueAnimator.ofFloat(value, val);
                      valueAnimator.setDuration(200);
                      valueAnimator.setInterpolator(interpolator);
                      valueAnimator.addUpdateListener(animation -> {
                          value = (float) animation.getAnimatedValue();
                          int thumbX = (int) ((value - min) / (max - min) * (getWidth() - getPaddingLeft() - getPaddingRight()) + getPaddingLeft());
                          int thumbY = getHeight() / 2;
                          int radius = rippleDrawable.getRadius();
                          rippleDrawable.setBounds(thumbX - radius, thumbY - radius, thumbX + radius, thumbY + radius);
                          postInvalidate();
                      });
                      valueAnimator.start();
                  }
                  if (radiusAnimator != null)
                      radiusAnimator.end();
                  radiusAnimator = ValueAnimator.ofFloat(thumbRadius, THUMB_RADIUS);
                  radiusAnimator.setDuration(200);
                  radiusAnimator.setInterpolator(interpolator);
                  radiusAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                      @Override
                      public void onAnimationUpdate(ValueAnimator animation) {
                          thumbRadius = (float) animation.getAnimatedValue();
                          postInvalidate();
                      }
                  });
                  radiusAnimator.start();
              } else {
                  if (style == Style.Discrete) {
                      float val2 = (float) Math.floor((value2 - min + step / 2) / step) * step + min;
                      if (valueAnimator != null)
                          valueAnimator.cancel();
                      valueAnimator = ValueAnimator.ofFloat(value2, val2);
                      valueAnimator.setDuration(200);
                      valueAnimator.setInterpolator(interpolator);
                      valueAnimator.addUpdateListener(animation -> {
                          value2 = (float) animation.getAnimatedValue();
                          int thumbX = (int) ((value2 - min) / (max - min) * (getWidth() - getPaddingLeft() - getPaddingRight()) + getPaddingLeft());
                          int thumbY = getHeight() / 2;
                          int radius = rippleDrawable.getRadius();
                          rippleDrawable.setBounds(thumbX - radius, thumbY - radius, thumbX + radius, thumbY + radius);
                          postInvalidate();
                      });
                      valueAnimator.start();
                  }
                  if (radiusAnimator != null)
                      radiusAnimator.end();
                  radiusAnimator = ValueAnimator.ofFloat(thumbRadius2, THUMB_RADIUS);
                  radiusAnimator.setDuration(200);
                  radiusAnimator.setInterpolator(interpolator);
                  radiusAnimator.addUpdateListener(animation -> {
                      thumbRadius2 = (float) animation.getAnimatedValue();
                      postInvalidate();
                  });
                  radiusAnimator.start();
              }
              //draggedThumb = -1;
              ViewParent parent = getParent();
              if (parent != null)
                  parent.requestDisallowInterceptTouchEvent(false);
              if (showLabel)
                  popup.dismiss();
          }
  
          if (draggedThumb == 1) {
              v = (event.getX() - getPaddingLeft()) / (getWidth() - getPaddingLeft() - getPaddingRight());
              v = Math.max(0, Math.min(v, 1));
          } else if (draggedThumb == 2) {
              v2 = (event.getX() - getPaddingLeft()) / (getWidth() - getPaddingLeft() - getPaddingRight());
              v2 = Math.max(0, Math.min(v2, 1));
          }
  
          if (v > v2) {
              draggedThumb = 3 - draggedThumb;
              float t = v;
              v = v2;
              v2 = t;
              t = thumbRadius;
              thumbRadius = thumbRadius2;
              thumbRadius2 = t;
          }
          float newValue = v * (max - min) + min;
          float newValue2 = v2 * (max - min) + min;
  
          int thumbX = 0;
          if (draggedThumb == 1) {
              thumbX = (int) (v * (getWidth() - getPaddingLeft() - getPaddingRight()) + getPaddingLeft());
          } else if (draggedThumb == 2) {
              thumbX = (int) (v2 * (getWidth() - getPaddingLeft() - getPaddingRight()) + getPaddingLeft());
          }
          int thumbY = getHeight() / 2;
          int radius = rippleDrawable.getRadius();
  
          if (showLabel && draggedThumb > 0) {
              int[] location = new int[2];
              getLocationInWindow(location);
              popup.setText(String.format(labelFormat, draggedThumb == 1 ? newValue : newValue2));
              popup.update(thumbX + location[0] - popup.getBubbleWidth() / 2, thumbY - radius + location[1] - popup.getHeight());
          }
  
          if (rippleDrawable != null) {
              rippleDrawable.setHotspot(event.getX(), event.getY());
              rippleDrawable.setBounds(thumbX - radius, thumbY - radius, thumbX + radius, thumbY + radius);
          }
  
          postInvalidate();
          if ((newValue != value || newValue2 != value2) && onValueChangedListener != null) {
              if (style == Style.Discrete) {
                  int sv = stepValue(newValue);
                  int sv2 = stepValue(newValue2);
                  if (stepValue(value) != sv || stepValue(value2) != sv2)
                      onValueChangedListener.onValueChanged(this, sv, sv2);
              } else {
                  onValueChangedListener.onValueChanged(this, newValue, newValue2);
              }
          }
          value = newValue;
          value2 = newValue2;
          super.onTouchEvent(event);
          return true;
      }