Horizo​​ntalScrollView 的无限平滑 scrollX

Infinite smooth scrollX for HorizontalScrollView

您将如何实现从左到右(反之亦然)的无限平滑水平滚动?

HorizontalScrollView 只包含一个 TextView 元素,里面有很长的文本,因此我想滚动该文本而不是用户。

我发现 ObjectAnimator 是实现平滑滚动的唯一方法。现在的问题是正确地循环它。我找到了两个接近的解决方案,尽管它们没有按预期工作:

  1. 使用CycleInterpolator()。无法实现流畅的行为:

    ObjectAnimator animRight = ObjectAnimator.ofInt(hScrollVIew, "scrollX", hScrollVIew.getRight()); animRight.setRepeatCount(ValueAnimator.INFINITE); animRight.setInterpolator(new CycleInterpolator(1f)); animRight.setDuration(4000); animRight.setStartDelay(0); animRight.start();

  2. 创建 2 个动画(左和右),它们会一个接一个地调用。此解决方案在第一个动画后有奇怪的延迟效果。

    final ObjectAnimator animRight = ObjectAnimator.ofInt(hScrollVIew, "scrollX", holder.hsvTitleHolder.getRight());
    animRight.setDuration(SCROLL_DURATION);
    
    final ObjectAnimator animLeft = ObjectAnimator.ofInt(hScrollVIew, "scrollX", 0);
    animLeft.setDuration(SCROLL_DURATION);
    
    animRight.addListener(new Animator.AnimatorListener() {
        Override
        public void onAnimationStart(Animator animation) {}
    
        @Override
        public void onAnimationEnd(Animator animation) {
            hScrollVIew.clearAnimation();
            animLeft.start();
        }
    
        @Override
        public void onAnimationCancel(Animator animation) {}
    
        @Override
        public void onAnimationRepeat(Animator animation) {}
    });
    
    animLeft.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {}
    
        @Override
        public void onAnimationEnd(Animator animation) {
            hScrollVIew.clearAnimation();
            animRight.start();
        }
    
        @Override
        public void onAnimationCancel(Animator animation) {}
    
        @Override
        public void onAnimationRepeat(Animator animation) {}
    });
    
    animRight.start();
    

如果有人遇到类似问题,请分享您的经验。

使用这样的代码:

    final HorizontalScrollView hsv = new HorizontalScrollView(this);
    final TextView tv = new TextView(this);
    tv.setTextSize(48);
    tv.setText("Our evil heaven for living is to yearn others agreeable.");
    hsv.addView(tv);
    setContentView(hsv);

    View.OnClickListener ocl = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ObjectAnimator animRight = ObjectAnimator.ofInt(hsv, "scrollX", 0, tv.getWidth() - hsv.getWidth());
            animRight.setRepeatCount(3);
            // you could use CycleInterpolator(0.5f) but the 
            // effect with CycleInterpolator is not so smooth
            // so use that custom Interpolator
            animRight.setInterpolator(new Interpolator() {
                @Override
                public float getInterpolation(float input) {
                    return (float) Math.pow(Math.sin(Math.PI * input), 2);
// you could also use similar interpolation:
//                    return (float) (1 - Math.cos(2 * Math.PI * input)) / 2;
                }
            });
            animRight.setDuration(4000);
            animRight.start();
        }
    };
    tv.setOnClickListener(ocl);