如何实现Buttery Smooth ViewPager Shake动画

Hec*_*tor 10 android android-animation android-viewpager

我正在研究当前项目中的Android ViewPager动画.

我想为我的用户提供与我的ViewPager相关的可供性.

我正在寻找它从左到右"摇动"ViewPager以部分显示所选页面的相邻页面的效果.

当用户选择第一页(F)时,我会在F和F + 1之间"摇动".

当用户选择最后一页(L)时,我会在L和L-1之间"摇动".

否则,当用户选择任何其他页面(X)时,我会在X-1,X和X + 1之间"摇动".

我尝试了以下方法,这些方法都给出了令人不满意的结果.

Fake drag using screen density to calculate shake distance and valueAnimator and ObjectAnimator.

Animating ViewPager.PageTransformer.
Run Code Online (Sandbox Code Playgroud)

我无法获得令人满意的"摇晃"效果.

我想实现一个Spring Dampening风格的动画.

FakeDrag是最接近的,虽然效果不可靠,但在我第一次开始动画时它似乎永远不会正常工作.

即使是FakeDrag也不会在页面滑动之间产生所需的平滑抖动.

我想在我的视图寻呼机上使用基于物理的动画但是看不清楚.

有可能实现我想要的动画吗?

UPDATE

我已经开发了这个代码,它可以产生预期的效果,但是它的JANKY!

 @Override
    protected void onResume() {
        super.onResume();

        final Handler handler = new Handler();
        handler.postDelayed(() -> animateViewPager(ANIMATION_OFFSET, ANIMATION_DURATION), ANIMATION_DELAY);
    }


  /**
     * @param offset
     * @param duration
     */
    private void animateViewPager(final int offset, final int duration) {
        if (animator.isRunning()) {
            return;
        }

        animator.removeAllUpdateListeners();
        animator.removeAllListeners();

        animator.setIntValues(0, -offset);
        animator.setDuration(duration);
        animator.setRepeatCount(getRepeatCount());
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.addUpdateListener(constructUpdateListener());

        animator.addListener(constructAnimatorListener());
        animator.start();

    }

    /**
     *
     * @return
     */
    private Animator.AnimatorListener constructAnimatorListener() {
        return new AnimatorListenerAdapter() {

            @Override
            public void onAnimationStart(final Animator animation) {
                animFactor = 1;
            }

            @Override
            public void onAnimationEnd(final Animator animation) {
                viewPager.endFakeDrag();
                if (xAnimation == null) {
                    xAnimation = createSpringAnimation(viewPager, SpringAnimation.X, 0, SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
                } else {
                    xAnimation.cancel();
                }

                viewPager.animate().x(viewPager.getWidth() * 0.1f).setDuration(0).start();
                xAnimation.start();
            }

            @Override
            public void onAnimationRepeat(final Animator animation) {
                animFactor = -1;
            }
        };
    }

    /**
     * @return
     */
    private int getRepeatCount() {
        if (isOnlyPage()) {
            return 0;
        }

        if (isFirstListItem()) {
            return REPEAT_ONCE;
        }

        if (isLastListItem()) {
            return REPEAT_ONCE;
        }

        return REPEAT_TWICE;
    }

    @SuppressWarnings("StatementWithEmptyBody")
    private ValueAnimator.AnimatorUpdateListener constructUpdateListener() {
        return animation -> {
            final Integer value = animFactor * (Integer) animation.getAnimatedValue();
            if (viewPager.isFakeDragging()) {
            } else {
                viewPager.beginFakeDrag();
            }
            viewPager.fakeDragBy(value);
        };
    }

    /**
     * @param view
     * @param property
     * @param finalPosition
     * @param stiffness
     * @param dampingRatio
     * @return
     */
    private SpringAnimation createSpringAnimation(final View view, final DynamicAnimation.ViewProperty property, final float finalPosition, final float stiffness, final float dampingRatio) {
        final SpringAnimation animation = new SpringAnimation(view, property);
        final SpringForce springForce = new SpringForce(finalPosition);
        springForce.setStiffness(stiffness);
        springForce.setDampingRatio(dampingRatio);
        animation.setSpring(springForce);
        return animation;
    }
Run Code Online (Sandbox Code Playgroud)