Android에서 뷰 페이저 어댑터로 스크롤 속도를 늦추는 방법이 있습니까?
아시다시피 저는이 코드를보고 있습니다. 나는 내가 뭘 잘못했는지 알아낼 수 없다.
try{
Field mScroller = mPager.getClass().getDeclaredField("mScroller");
mScroller.setAccessible(true);
Scroller scroll = new Scroller(cxt);
Field scrollDuration = scroll.getClass().getDeclaredField("mDuration");
scrollDuration.setAccessible(true);
scrollDuration.set(scroll, 1000);
mScroller.set(mPager, scroll);
}catch (Exception e){
Toast.makeText(cxt, "something happened", Toast.LENGTH_LONG).show();
}
아무것도 변경하지 않지만 예외가 발생하지 않습니까?
답변
나는 실제로 mScroller 필드를 변경 한 HighFlyer의 코드로 시작했지만 (훌륭한 시작) ViewPager가 스크롤을 요청할 때 mScroller에 기간을 명시 적으로 전달하기 때문에 스크롤 기간을 연장하는 데 도움이되지 않았습니다.
ViewPager 확장은 중요한 메서드 (smoothScrollTo)를 재정의 할 수 없기 때문에 작동하지 않았습니다.
이 코드로 Scroller를 확장하여이 문제를 해결했습니다.
public class FixedSpeedScroller extends Scroller {
private int mDuration = 5000;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
}
다음과 같이 사용합니다.
try {
Field mScroller;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(mPager.getContext(), sInterpolator);
// scroller.setFixedDuration(5000);
mScroller.set(mPager, scroller);
} catch (NoSuchFieldException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
기본적으로 기간을 5 초로 하드 코딩하고 ViewPager에서 사용하도록했습니다.
도움이 되었기를 바랍니다.
답변
나는 스스로하고 싶었고 해결책을 얻었습니다 (그러나 반사를 사용하여). 허용되는 솔루션과 유사하지만 동일한 보간기를 사용하고 요인에 따라 기간 만 변경합니다. 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 {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
Field interpolator = viewpager.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() - ( forward ? viewPager.getPaddingLeft() : viewPager.getPaddingRight() ));
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);
viewPager.beginFakeDrag();
animator.start();
}
답변
당신이 할 수있는대로 ViewPager 소스에서 볼 있듯이 mScroller 개체에 의해 제어되는 플링 기간입니다. 에서 documantation 우리는 읽을 수 있습니다 :
스크롤 기간은 생성자에 전달 될 수 있으며 스크롤 애니메이션에 걸리는 최대 시간을 지정합니다.
따라서 속도를 제어하려면 반사를 통해 mScroller 객체를 변경할 수 있습니다.
다음과 같이 작성해야합니다.
setContentView(R.layout.main);
mPager = (ViewPager)findViewById(R.id.view_pager);
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
mScroller.set(mPager, scroller); // initialize scroller object by yourself
답변
이것은 완벽한 해결책이 아니며 속도를 느리게 만들 수는 없습니다 int
. 하지만 저에게는 충분히 느리고 반사를 사용할 필요가 없습니다.
클래스가있는 패키지를 확인하십시오. smoothScrollTo
패키지 가시성이 있습니다.
package android.support.v4.view;
import android.content.Context;
import android.util.AttributeSet;
public class SmoothViewPager extends ViewPager {
private int mVelocity = 1;
public SmoothViewPager(Context context) {
super(context);
}
public SmoothViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
void smoothScrollTo(int x, int y, int velocity) {
//ignore passed velocity, use one defined here
super.smoothScrollTo(x, y, mVelocity);
}
}
답변
ViewPager의 fakeDrag 메서드는 대체 솔루션을 제공하는 것 같습니다.
예를 들어 이것은 항목 0에서 1로 페이지를 표시합니다.
rootView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
ViewPager pager = (ViewPager) getActivity().findViewById(R.id.pager);
//pager.setCurrentItem(1, true);
pager.beginFakeDrag();
Handler handler = new Handler();
handler.post(new PageTurner(handler, pager));
}
});
private static class PageTurner implements Runnable {
private final Handler handler;
private final ViewPager pager;
private int count = 0;
private PageTurner(Handler handler, ViewPager pager) {
this.handler = handler;
this.pager = pager;
}
@Override
public void run() {
if (pager.isFakeDragging()) {
if (count < 20) {
count++;
pager.fakeDragBy(-count * count);
handler.postDelayed(this, 20);
} else {
pager.endFakeDrag();
}
}
}
}
( count * count
가는 동안 드래그 속도를 높이기 위해 있습니다)
답변
나는 사용했다
DecelerateInterpolator ()
다음은 그 예입니다.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
Field mScroller = null;
try {
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
Scroller scroller = new Scroller(this, new DecelerateInterpolator());
mScroller.set(mViewPager, scroller);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}