[Android] ViewPagerの遷移アニメーションをカスタマイズする

  • 7
    Like
  • 0
    Comment
  • 以前からAndroidで標準で用意されている仕組み
  • ViewPager.PageTransformer を実装(implements)したクラスを作成し ViewPager にセットする
someViewPager.setPageTransformer(
        true,
        new SomeTransformer()
);
  • 第一引数(boolean: reverseDrawingOrder)は1枚目のページを2枚目以降のページの上に描画するか否か

汎用的に利用できる PageTransformer を作っておくと便利


PageSwipeTransformer.java
public class PageSwipeTransformer implements ViewPager.PageTransformer {
    private float minAlphaOut = 1.0F;
    private float minAlphaIn = 1.0F;
    private float minScaleOut = 1.0F;
    private float minScaleIn = 1.0F;
    private float positionXOffsetIn = 1.0F;
    private float positionXOffsetOut = -1.0F;
    private float positionYOffsetIn = 0.0F;
    private float positionYOffsetOut = 0.0F;

    public PageSwipeTransformer setMinAlphaOut(float minAlpha) {
        this.minAlphaOut = minAlpha;
        return this;
    }

    public PageSwipeTransformer setMinAlphaIn(float minAlpha) {
        this.minAlphaIn = minAlpha;
        return this;
    }

    public PageSwipeTransformer setMinScaleOut(float minScale) {
        this.minScaleOut = minScale;
        return this;
    }

    public PageSwipeTransformer setMinScaleIn(float minScale) {
        this.minScaleIn = minScale;
        return this;
    }

    public PageSwipeTransformer setPositionXOffsetIn(float offsetPositionX) {
        this.positionXOffsetIn = offsetPositionX;
        return this;
    }

    public PageSwipeTransformer setPositionXOffsetOut(float offsetPositionX) {
        this.positionXOffsetOut = offsetPositionX;
        return this;
    }

    public PageSwipeTransformer setPositionYOffsetIn(float offsetPositionY) {
        this.positionYOffsetIn = offsetPositionY;
        return this;
    }

    public PageSwipeTransformer setPositionYOffsetOut(float offsetPositionY) {
        this.positionYOffsetOut = offsetPositionY;
        return this;
    }

    @Override
    public void transformPage(View page, float position) {
        final float width = (float) page.getWidth();
        final float height = (float) page.getHeight();

        if (-1.0F < position && position <= 0) {
            page.setVisibility(View.VISIBLE);
            page.setAlpha(Math.max(minAlphaOut, 1 + position));
            page.setScaleX(Math.max(minScaleOut, 1 + position));
            page.setScaleY(Math.max(minScaleOut, 1 + position));
            page.setTranslationX(width * -position + width * -position * positionXOffsetOut);
            page.setTranslationY(height * -position * positionYOffsetOut);
        }

        if (0 < position && position < 1.0F) {
            page.setVisibility(View.VISIBLE);
            page.setAlpha(Math.max(minAlphaIn, 1 - position));
            page.setScaleX(Math.max(minScaleIn, 1 - position));
            page.setScaleY(Math.max(minScaleIn, 1 - position));
            page.setTranslationX(-width * position + width * position * positionXOffsetIn);
            page.setTranslationY(height * position * positionYOffsetIn);
        }

        if (position <= -1.0F || 1.0F <= position) {
            page.setVisibility(View.GONE);
        }
    }
}

例①: 縮小してスライド

viewPager.setPageTransformer(
        true,
        new PageSwipeTransformer()
                .setMinScaleOut(0.9F)
                .setMinScaleIn(0.9F)
);

  • 動作イメージ


例②: スライドアウト

viewPager.setPageTransformer(
        true,
        new PageSwipeTransformer()
                .setPositionXOffsetIn(0.0F)
);

  • 動作イメージ


例③: スライドイン

viewPager.setPageTransformer(
        false,
        new PageSwipeTransformer()
                .setPositionXOffsetOut(0.0F)
);

  • 動作イメージ


例④: スライドアウト + スタック(重なっている)

viewPager.setPageTransformer(
        true,
        new PageSwipeTransformer()
                .setPositionXOffsetIn(0.5F)
);

  • 動作イメージ


例⑤: フェードイン

viewPager.setPageTransformer(
        false,
        new PageSwipeTransformer()
                .setPositionXOffsetOut(0.0F)
                .setMinAlphaIn(0.0F)
                .setPositionXOffsetIn(0.0F)
);

  • 動作イメージ


例⑥: 拡大して現れる

viewPager.setPageTransformer(
        true,
        new PageSwipeTransformer()
                .setPositionXOffsetIn(0.0F)
                .setMinScaleIn(0.5F)
);

  • 動作イメージ


例⑦: 斜め上にスライド

viewPager.setPageTransformer(
        true,
        new PageSwipeTransformer()
                .setPositionYOffsetOut(-0.5F)
                .setPositionYOffsetIn(0.5F)
);

  • 動作イメージ


おまけ:コードで ViewPager のページを変更すると速すぎる問題


  • setCurrentItem() の第二引数(boolean: smoothScroll) に true を指定してもスムーズになってくれない
  • 解決するには ViewPager を継承したカスタムViewを作る

SmoothScrollViewPager.java
public class SmoothScrollViewPager extends ViewPager {

    public SmoothScrollViewPager(Context context) {
        super(context);
        setMyScroller();
    }

    public SmoothScrollViewPager(Context context, AttributeSet attr) {
        super(context, attr);
        setMyScroller();
    }

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

    private static class MyScroller extends Scroller {
        private MyScroller(Context context) {
            super(context, new FastOutSlowInInterpolator());
        }

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

  • Interpolator(前項の例だとFastOutSlowInInterpolator)とアニメーション時間(前項の例だと500ミリ秒)はお好みで
    • レイアウトXMLから指定できるようにすると良いかもしれない

END