ProgramingTip

프로그래밍 방식으로 혁신 할 때 ViewPager 애니메이션 기간 변경

bestdevel 2020. 11. 7. 10:18
반응형

프로그래밍 방식으로 혁신 할 때 ViewPager 애니메이션 기간 변경


슬라이드를 변경하고 있습니다.

viewPager.setCurrentItem(index++, true);

그러나 그것은 빠르게 변합니다. 애니메이션 속도를 수동으로 설정하는 방법이 있습니까?


나는 스스로를 믿습니다. 아직 테스트하지 나는 않은하지만 해야 우리 일을하거나 최소한의 수정이 필요합니다. Galaxy Nexus JB 4.2.1에서 테스트되었습니다. ViewPagerCustomDuration대신 XML에서 를 사용 ViewPager하며 다음을 수행 할 수 있습니다.

ViewPagerCustomDuration vp = (ViewPagerCustomDuration) findViewById(R.id.myPager);
vp.setScrollDurationFactor(2); // make the animation twice as slow

ViewPagerCustomDuration.java:

import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.animation.Interpolator;

import java.lang.reflect.Field;

public class ViewPagerCustomDuration extends ViewPager {

    public ViewPagerCustomDuration(Context context) {
        super(context);
        postInitViewPager();
    }

    public ViewPagerCustomDuration(Context context, AttributeSet attrs) {
        super(context, attrs);
        postInitViewPager();
    }

    private ScrollerCustomDuration mScroller = null;

    /**
     * Override the Scroller instance with our own class so we can change the
     * duration
     */
    private void postInitViewPager() {
        try {
            Field scroller = ViewPager.class.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            Field interpolator = ViewPager.class.getDeclaredField("sInterpolator");
            interpolator.setAccessible(true);

            mScroller = new ScrollerCustomDuration(getContext(),
                    (Interpolator) interpolator.get(null));
            scroller.set(this, mScroller);
        } catch (Exception e) {
        }
    }

    /**
     * Set the factor by which the duration will change
     */
    public void setScrollDurationFactor(double scrollFactor) {
        mScroller.setScrollDurationFactor(scrollFactor);
    }

}

ScrollerCustomDuration.java:

import android.annotation.SuppressLint;
import android.content.Context;
import android.view.animation.Interpolator;
import android.widget.Scroller;

public class ScrollerCustomDuration extends Scroller {

    private double mScrollFactor = 1;

    public ScrollerCustomDuration(Context context) {
        super(context);
    }

    public ScrollerCustomDuration(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }

    @SuppressLint("NewApi")
    public ScrollerCustomDuration(Context context, Interpolator interpolator, boolean flywheel) {
        super(context, interpolator, flywheel);
    }

    /**
     * Set the factor by which the duration will change
     */
    public void setScrollDurationFactor(double scrollFactor) {
        mScrollFactor = scrollFactor;
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor));
    }

}

이것이 누군가를 돕기를 바랍니다!


@ df778899의 답변Android ValueAnimator API를 기반으로 더 나은 솔루션을 찾았습니다 . 반사없이 잘 작동하며 매우 유연합니다. 또한 사용자 정의 ViewPager를 작성하여 android.support.v4.view 패키지에 넣을 필요가 없습니다. 다음은 예입니다.

private void animatePagerTransition(final boolean forward) {

    ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth());
    animator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            viewPager.endFakeDrag();
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            viewPager.endFakeDrag();
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
        }
    });

    animator.setInterpolator(new AccelerateInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        private int oldDragPosition = 0;

        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int dragPosition = (Integer) animation.getAnimatedValue();
            int dragOffset = dragPosition - oldDragPosition;
            oldDragPosition = dragPosition;
            viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1));
        }
    });

    animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS);
    if (viewPager.beginFakeDrag()) {
        animator.start();
    }
}

최신 정보 :

이 솔루션을 사용하여 한 번에 여러 페이지를 스 와이프 할 수 있는지 확인했습니다 (예 : 첫 페이지가 마지막 페이지 다음에 표시되어야하는 경우). 지정된 페이지 수를 처리하기 위해 약간 수정 된 코드입니다.

private int oldDragPosition = 0;

private void animatePagerTransition(final boolean forward, int pageCount) {
    // if previous animation have not finished we can get exception
    if (pagerAnimation != null) {
        pagerAnimation.cancel();
    }
    pagerAnimation = getPagerTransitionAnimation(forward, pageCount);
    if (viewPager.beginFakeDrag()) {    // checking that started drag correctly
        pagerAnimation.start();
    }
}

private Animator getPagerTransitionAnimation(final boolean forward, int pageCount) {
    ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth() - 1);
    animator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            viewPager.endFakeDrag();
        }

        @Override
        public void onAnimationCancel(Animator animation) {
            viewPager.endFakeDrag();
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            viewPager.endFakeDrag();
            oldDragPosition = 0;
            viewPager.beginFakeDrag();
        }
    });

    animator.setInterpolator(new AccelerateInterpolator());
    animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int dragPosition = (Integer) animation.getAnimatedValue();
            int dragOffset = dragPosition - oldDragPosition;
            oldDragPosition = dragPosition;
            viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1));
        }
    });

    animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS / pageCount); // remove divider if you want to make each transition have the same speed as single page transition
    animator.setRepeatCount(pageCount);

    return animator;
}

 public class PresentationViewPager extends ViewPager {

    public static final int DEFAULT_SCROLL_DURATION = 250;
    public static final int PRESENTATION_MODE_SCROLL_DURATION = 1000;

    public PresentationViewPager (Context context) {
        super(context);
    }

    public PresentationViewPager (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setDurationScroll(int millis) {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new OwnScroller(getContext(), millis));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public class OwnScroller extends Scroller {

        private int durationScrollMillis = 1;

        public OwnScroller(Context context, int durationScroll) {
            super(context, new DecelerateInterpolator());
            this.durationScrollMillis = durationScroll;
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, durationScrollMillis);
        }
    }
}

더 나은 솔루션은 지원 패키지에서 클래스를 만들어 개인 필드에 액세스하는 것입니다. 편집클래스에 MAX_SETTLE_DURATION의해 작성된 600ms에 바인딩 ViewPager됩니다.

package android.support.v4.view;

import android.content.Context;
import android.util.AttributeSet;

public class SlowViewPager extends ViewPager {

    // The speed of the scroll used by setCurrentItem()
    private static final int VELOCITY = 200;

    public SlowViewPager(Context context) {
        super(context);
    }

    public SlowViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
        setCurrentItemInternal(item, smoothScroll, always, VELOCITY);
    }

}

XML을 사용하여 접근 할 수 있습니다.


다음은 Librera Reader 에서 사용되는 코드입니다.

public class MyViewPager extends ViewPager {

  public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        initMyScroller();
    }

    private void initMyScroller() {
        try {
            Class<?> viewpager = ViewPager.class;
            Field scroller = viewpager.getDeclaredField("mScroller");
            scroller.setAccessible(true);
            scroller.set(this, new MyScroller(getContext())); // my liner scroller

            Field mFlingDistance = viewpager.getDeclaredField("mFlingDistance");
            mFlingDistance.setAccessible(true);
            mFlingDistance.set(this, Dips.DP_10);//10 dip

            Field mMinimumVelocity = viewpager.getDeclaredField("mMinimumVelocity");
            mMinimumVelocity.setAccessible(true);
            mMinimumVelocity.set(this, 0); //0 velocity

        } catch (Exception e) {
            LOG.e(e);
        }

    }

    public class MyScroller extends Scroller {
        public MyScroller(Context context) {
            super(context, new LinearInterpolator()); // my LinearInterpolator
        }

        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, 175);//175 duration
        }
    }

 }

하루 종일 낭비한 후 offscreenPageLimit을 총 no로 설정 한 솔루션을 찾았습니다. 페이지의.

일정한 길이의 ViewPager 스크롤을 부드럽게 유지하기 위해 setOffScreenLimit (page.length)는 모든 뷰를 메모리에 유지합니다. 그러나 이것은 View.requestLayout 함수 호출을 포함하는 모든 애니메이션 (예 : 여백 또는 경계 변경과 관련된 모든 애니메이션)에 문제가됩니다. 메모리에있는 모든 뷰가 무효화되기 때문에 (Romain Guy에 따라) 정말 느려집니다. 그래서 매끄럽게 만들기 위해 몇 가지 다른 방법을 시도했지만 requestLayout 및 기타 무효화 메서드를 재정의하면 다른 많은 문제가 발생합니다.

좋은 타협은 화면 밖 제한을 동적으로 수정하여 페이지 사이의 대부분의 스크롤이 매우 부드러워지면서 사용자가 뷰를 제거하여 모든 페이지 내 애니메이션이 매끄럽게되도록하는 것입니다. 이것은 메모리에서 다른 뷰를 만들어야하는 뷰가 1 개 또는 2 개뿐 일 때 정말 잘 작동합니다.

*** feset limit u를 설정하면 모든 조각을 동시에로드하므로 솔루션이 작동하지 않을 때 사용합니다.

참고 URL : https://stackoverflow.com/questions/10812009/change-viewpager-animation-duration-when-sliding-programmatically

반응형