LoginSignup
34
29

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-08-28
1 / 23
  • 以前から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

34
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
29