code: public ValueAnimator animateScroll(final int scrollY) {
  
          // create an instance of this animator that is shared between calls
          if (mManualScrollAnimator == null) {
              mManualScrollAnimator = ValueAnimator.ofFloat(.0F, 1.F);
              mManualScrollAnimator.setEvaluator(new FloatEvaluator());
              mManualScrollAnimator.addListener(new SelfUpdateAnimationListener());
          } else {
  
              // unregister our update listener
              if (mManualScrollUpdateListener != null) {
                  mManualScrollAnimator.removeUpdateListener(mManualScrollUpdateListener);
              }
  
              // cancel if running
              if (mManualScrollAnimator.isRunning()) {
                  mManualScrollAnimator.end();
              }
          }
  
          final int y;
          if (scrollY < 0) {
              y = 0;
          } else if (scrollY > mMaxScrollY) {
              y = mMaxScrollY;
          } else {
              y = scrollY;
          }
  
          final int startY = getScrollY();
          final int diff = y - startY;
  
          mManualScrollUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
              @Override
              public void onAnimationUpdate(ValueAnimator animation) {
                  final float fraction = animation.getAnimatedFraction();
                  scrollTo(0, (int) (startY + (diff * fraction) + .5F));
              }
          };
          mManualScrollAnimator.addUpdateListener(mManualScrollUpdateListener);
  
          return mManualScrollAnimator;
      }
docs: Helper method to animate scroll state of ScrollableLayout.
  Please note, that returned {@link ValueAnimator} is not fully configured -
  it needs at least `duration` property.
  Also, there is no checks if the current scrollY is equal to the requested one.
  @param scrollY the final scroll y to animate to
  @return {@link ValueAnimator} configured to animate scroll state