docs: @Override
      public boolean onTouchEvent(MotionEvent event) {
          if (!isEnabled())
              return false;
  
          if (event.getAction() == MotionEvent.ACTION_DOWN) {
              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.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 (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(animation -> {
                  thumbRadius = (float) animation.getAnimatedValue();
                  postInvalidate();
              });
              radiusAnimator.start();
              ViewParent parent = getParent();
              if (parent != null)
                  parent.requestDisallowInterceptTouchEvent(false);
              if (showLabel)
                  popup.dismiss();
          }
  
          float v = (event.getX() - getPaddingLeft()) / (getWidth() - getPaddingLeft() - getPaddingRight());
          v = Math.max(0, Math.min(v, 1));
          float newValue = v * (max - min) + min;
  
          int thumbX = (int) (v * (getWidth() - getPaddingLeft() - getPaddingRight()) + getPaddingLeft());
          int thumbY = getHeight() / 2;
          int radius = rippleDrawable.getRadius();
  
          if (showLabel) {
              int[] location = new int[2];
              getLocationInWindow(location);
              popup.setText(String.format(labelFormat, newValue));
              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 && onValueChangedListener != null) {
              if (style == Style.Discrete) {
                  int sv = stepValue(newValue);
                  if (stepValue(value) != sv)
                      onValueChangedListener.onValueChanged(this, sv);
              } else {
                  onValueChangedListener.onValueChanged(this, newValue);
              }
          }
          value = newValue;
          super.onTouchEvent(event);
          return true;
      }