2018年2月24日土曜日

【Android】ViewPager

  • 公開日:2018年02月23日

記事概要

java-programming向けの詳細な記事を書く時間が取れないので、ざっくりとこちらに情報を載せます。
ViewPagerアニメーションの学習と研究をしていたので、そのまとめ記事です。

環境

  • Android Studio 3.0.1

概要

ViewPagerはよく使いますが、きちんと内部コードを追って学習したことはほとんどありませんでした。
記事の内容は、この公式ドキュメントがベースです。さらに深掘りしています。

ViewPagerとPageTransformer

ViewPagerのアニメーション方法を変更するには、ViewPager.PageTransformerを使います。ViewPager.PageTransformerはtransformPageが宣言されているInterfaceです。

ViewPager.java

    public interface PageTransformer {
        /**
         * Apply a property transformation to the given page.
         *
         * @param page Apply the transformation to this page
         * @param position Position of page relative to the current front-and-center
         *                 position of the pager. 0 is front and center. 1 is one full
         *                 page position to the right, and -1 is one page position to the left.
         */
        void transformPage(@NonNull View page, float position);
    }

画面切り替え時にtransformPageメソッドが呼び出されます。

PageTransformerで実装した内容を有効にするには、setPageTransformerメソッドを使います。

ViewPager.java

mPager.setPageTransformer(true, new SamplePageTransformer());

上記のように設定すると、実装した具体的なPageTransformerクラスがmPageTransformer変数に設定され、onPageScrolledメソッドで呼び出されます。

ViewPager.java

        if (mPageTransformer != null) {
            final int scrollX = getScrollX();
            final int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                final View child = getChildAt(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();

                if (lp.isDecor) continue;
                final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();
                mPageTransformer.transformPage(child, transformPos);
            }
        }

PageTransformerクラスの実装

具体的なPageTransformerクラスは、PageTransformerをimplementsして実装します。サンプルとしてZoomOutPageTransformerクラスを実装してみます。

{project_folder}/ZoomOutPageTransformer.java

public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.5f;

    @Override
    public void transformPage(@NonNull View page, float position) {
        int pageWidth = page.getWidth();
        int pageHeight = page.getHeight();

        Log.d("ZoomOutPage", "position :" + position + ", view id : " + page.getId());
        Log.d("ZoomOutPage", "pageWidth :" + pageWidth + ", view id : " + page.getId());
        Log.d("ZoomOutPage", "pageWidth :" + pageHeight + ", view id : " + page.getId());

        if (position  < -1) {
            // 透明にする
            page.setAlpha(0.0f);
        } else if (position <= 1) {
            // -1 < posiiton < 1
            // 多分、徐々に小さくするため
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            // margin 黒枠のところ
            // 縦 top bottomやな
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            // 水平 名前が left rightだと
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
//            if (position < 0) {
//                // 相対的に動かす。これが無いと画像が動かないのでおかしくなるはず。
//                page.setTranslationX(horzMargin - vertMargin / 2);
//            } else {
//                page.setTranslationX(-horzMargin + vertMargin / 2);
//            }

            // Scale the page down (between MIN_SCALE and 1)
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);

            // Fade the page relative to its size.
            page.setAlpha(MIN_ALPHA +
                    (scaleFactor - MIN_SCALE) /
                            (1 - MIN_SCALE) * (1 - MIN_ALPHA));

        } else {
            // 透明にする
            page.setAlpha(0.0f);
        }


    }
}

positionはページ数でなく、引数のページの相対的な位置です。-1 < x < 1までの範囲の値をとり、0が中央, -1が左, 1が右となります。

vertMarginとhorzMarginはページ切り替え時に、ページ間のviewの距離を詰めるための計算に使っています。setTranslationXでviewの位置をずらすことで、ページ移動のアニメーションをスムーズに見せています。名称がわかりにくいので、topBottomMarginとleftRightMarginで実装した方がわかりやすいと思います。

続いて、DepthPageTransformerを実装してみます。

{project_folder}/DepthPageTransformer.java

public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;
    @Override
    public void transformPage(@NonNull View page, float position) {
        int pageWidth = page.getWidth();

        if (position < -1) {
            // 透明にする
            page.setAlpha(0.0f);
        } else if (position <= 0) {
            // [-1 : 0]
            // Use the default slide transition when moving to the left page
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);

        } else if (position <= 1) {
            // [0 : 1]
            // Fade the page out.
            page.setAlpha(1 - position);

            // Counteract the default slide transition
            page.setTranslationX(pageWidth * -position);

            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
        } else {
            // 透明にする
            page.setAlpha(0.0f);
        }
    }
}

こちらの方が理解しやすですね。左と右で綺麗に処理が分割されています。position <= 0, つまり左側はただスライドするだけです。

page.setAlphaで透過状態を管理しています。徐々に薄くなったり、濃くなったりしています。
ズームも同じで、大から小, 小から大へとviewを変化させています。setScaleX, setScaleYで拡大縮小をしています。

page.setTranslationX(pageWidth * -position);で画面が停止しているように見えるようにしています。

結論

ViewPager.PageTransformerを使うことで、アニメーションを実装できます。色々とやってみようと思います。

PICK UP

運営サイト


参考


この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

0 件のコメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...