pagetransformer实现_自定义pagetransformer实现垂直翻转 - CSDN
精华内容
参与话题
  • 从Android 3.0开始,ViewPager提供了PageTransformer接口来帮助应用方便实现各种切换效果,该接口是在ViewPager滑动的时候被调用的,下面是其定义:/** * A PageTransformer is invoked whenever a visible/...

    一,PageTransformer 的简单介绍
    从Android 3.0开始,ViewPager提供了PageTransformer接口来帮助应用方便实现各种切换效果,该接口是在ViewPager滑动的时候被调用的,下面是其定义:

    /**
     * A PageTransformer is invoked whenever a visible/attached page is scrolled.
     * This offers an opportunity for the application to apply a custom transformation
     * to the page views using animation properties.
     *
     * <p>As property animation is only supported as of Android 3.0 and forward,
     * setting a PageTransformer on a ViewPager on earlier platform versions will
     * be ignored.</p>
     */
    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.
          */
         public void transformPage(View page, float position);
    }

    从上面可以看出ViewPager实现各种Page页面变换的动画效果只要实现transformPage这一个方法即可,其中:
    (1)page
    用来表示当前被滑动的页面所对应的view,通过实际的使用会发现,滑动的时候其返回的page并不都是同一个对象,因为滑动不仅导致当前界面慢慢滑出屏幕,同时导致相关的新界面慢慢滑入屏幕,下面是通过源码查看其被调用的地方:

    protected void onPageScrolled(int position, float offset, int offsetPixels) {
         ...
         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);
             }
         }
         ...
    }

    可以看出,每次滑动时,都会依次取ViewPager中每个child然后调用transformPage方法,验证了上面我们说明的每次滑动时返回的page是可能不同的。
    (2)position
    给定界面的位置相对于屏幕中心的偏移量。在用户滑动界面的时候,是动态变化的。假设ViewPager中有A,B,C页面,当前停留在B界面,则B界面此时的position为0,A界面的position为-1,C界面的position为1,而后向左滑动界面(C -> B),此过程中A的position在区间(-Infinity,-1)变化,B的position在区间[-1,0)变化,C的position在区间[0,1)变化,并且会发现B的position跟C的position绝对值之和为1,而正负则表示了滑入和滑出状态。理解清楚了position的变化过程对后面如何利用PageTransformer实现各种变化是很有用的。
    当应用实现好了PageTransformer接口后,就可以通过ViewPager提供的setPageTransformer()设置进去。

        public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer)
    

    reverseDrawingOrder用来指定是否要改变page的绘制顺序,在getChildDrawingOrder()时会用到,true则表示从最后一个开始绘制。
    通过对position的介绍可知,我们在实现PageTransformer时主要还是关注[-1,1] 区间的值。
    首先拿最简单的AlphaPageTransformer变换来说,其实现如下:

    public class AlphaPageTransformer implements ViewPager.PageTransformer {
        private float mMinAlpha = 0.5f;
    
        public void transformPage(View view, float position) {
            if (position < -1) {
                view.setAlpha(mMinAlpha);
            } else if (position <= 0) {
                float factor = mMinAlpha + (1 - mMinAlpha) * (1 + position);
                view.setAlpha(factor);
            } else if(position <= 1){
                float factor = mMinAlpha + (1 - mMinAlpha) * (1 - position);
                view.setAlpha(factor);
            } else {
                view.setAlpha(mMinAlpha);
            }
        }
    }

    可以总结出一套通用简单的规律:

    public class DepthPageTransformer implements ViewPager.PageTransformer {
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
    
            if (position < -1) {
               //具体实现,此时page在界面的左边并且已经不显示在当前界面
            } else if (position <= 0) {
                //具体实现,此时page正从中间往左侧移动
            } else if (position <= 1) {
               //具体实现,此时page正从右侧往中间移动
            } else {
              //具体实现,此时page在界面的右边并且已经不显示在当前界面
            }
        }
    }

    三,如何实现视差滚动效果
    视差滚动效果也是最近几年在手机上比较流行,一般应用场景是首次启动应用时的导航界面,根据上面的规律,结合自己的效果实现动画就可以了。只需在PageTransformer中先找到相关的view,然后根据position设置不同的水平平移距离即可,大致的伪代码如下所示:

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
    
        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);
    
        } else if (position <= 1) { // [-1,1]
    
            mBlur.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth));
            mBlurLabel.setTranslationX((float) (-(1 - position) * 0.5 * pageWidth));
    
            mDim.setTranslationX((float) (-(1 - position) * pageWidth));
            mDimLabel.setTranslationX((float) (-(1 - position) * pageWidth));
    
            mCheck.setTranslationX((float) (-(1 - position) * 1.5 * pageWidth));
            mDoneButton.setTranslationX((float) (-(1 - position) * 1.7 * pageWidth)); 
            // The 0.5, 1.5, 1.7 values you see here are what makes the view move in a different speed.
            // The bigger the number, the faster the view will translate.
            // The result float is preceded by a minus because the views travel in the opposite direction of the movement.
    
            mFirstColor.setTranslationX((position) * (pageWidth / 4));
    
            mSecondColor.setTranslationX((position) * (pageWidth / 1));
    
            mTint.setTranslationX((position) * (pageWidth / 2));
    
            mDesaturate.setTranslationX((position) * (pageWidth / 1));
            // This is another way to do it
    
    
        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }

    四,与OnPageChangeListener的不同
    OnPageChangeListener是很早就在ViewPager上提供的接口,其主要提供了在Page滑动时的一些回调,方便应用进行相关逻辑处理。

       /**
         * Callback interface for responding to changing state of the selected page.
         */
        public interface OnPageChangeListener {
    
            /**
             * This method will be invoked when the current page is scrolled, either as part
             * of a programmatically initiated smooth scroll or a user initiated touch scroll.
             *
             * @param position Position index of the first page currently being displayed.
             *                 Page position+1 will be visible if positionOffset is nonzero.
             * @param positionOffset Value from [0, 1) indicating the offset from the page at position.
             * @param positionOffsetPixels Value in pixels indicating the offset from position.
             */
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
    
            /**
             * This method will be invoked when a new page becomes selected. Animation is not
             * necessarily complete.
             *
             * @param position Position index of the new selected page.
             */
            public void onPageSelected(int position);
    
            /**
             * Called when the scroll state changes. Useful for discovering when the user
             * begins dragging, when the pager is automatically settling to the current page,
             * or when it is fully stopped/idle.
             *
             * @param state The new scroll state.
             * @see ViewPager#SCROLL_STATE_IDLE
             * @see ViewPager#SCROLL_STATE_DRAGGING
             * @see ViewPager#SCROLL_STATE_SETTLING
             */
            public void onPageScrollStateChanged(int state);
        }

    里面的onPageScrolled()方法也会在page滚动时会被实时调用,但是里面的position只是当前正在滚动页所在的position。按照上节动画的实现过程,一般来说,需要先找当前页和相邻页,然后根据偏移量对其添加动画,而onPageScrolled并不能提供所有相关页的信息,仅仅只是当前页的position,如果需要知道相邻页,就需要额外采取一些手段,更加详细的介绍可以参考http://blog.csdn.net/lmj623565791/article/details/38026503 里面的说明。当然如果非要通过OnPageChangeListener来实现以上的动画效果,也是可以的,这方面最出名的开源项目要数JazzyViewPager(https://github.com/jfeinstein10/JazzyViewPager) ,作者会先在ViewPager的Adapter中维护一个position与page对应关系的HashMap,然后在onPageScrolled()方法中就可以根据这个HashMap很方便的找到当前页以及相邻的页面,从而进行相关动画的设置。
    正是因为通过onPageScrolled()来实现动画比较困难,所以后来ViewPager提供了PageTransformer ,更加方便应用来实现各种动画效果
    相关参考文档:
    http://blog.csdn.net/lmj623565791/article/details/38026503
    http://blog.csdn.net/lmj623565791/article/details/51339751
    http://www.lightskystreet.com/2014/12/15/viewpager-anim/
    http://ryanhoo.github.io/blog/2014/07/16/step-by-step-implement-parallax-animation-for-splash-screen-of-zhihu/

    各种炫酷的page变换效果
    https://github.com/hongyangAndroid/MagicViewPager
    https://github.com/daimajia/AndroidImageSlider
    https://github.com/jfeinstein10/JazzyViewPager

    各种视差滚动效果
    https://github.com/Cleveroad/slidingtutorial-android
    https://github.com/stephentuso/welcome-android
    https://github.com/MoshDev/BackgroundViewPager
    https://github.com/andraskindler/parallaxviewpager

    展开全文
  • PageTransformer

    千次阅读 2013-05-10 09:39:25
    对于屏幕切换使用ViewPager 创建视图 创建一个布局文件,之后你将把它用作fragment的内容。 ? 代码片段,双击复制 01 02 03 04 05 ...<com.example.andro
    对于屏幕切换使用ViewPager

    创建视图

    创建一个布局文件,之后你将把它用作fragment的内容。
    ?
    代码片段,双击复制
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    <com.example.android.animationsdemo.ScrollView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
      
            <TextView style="?android:textAppearanceMedium"
                android:padding="16dp"
                android:lineSpacingMultiplier="1.2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/lorem_ipsum" />
      
    </com.example.android.animationsdemo.ScrollView>


    创建Fragment

    创建一个Fragment类,在onCreateView()中返回刚才创建的布局。当你需要一个新的页面
    来展示给用户时,你可以创建一个该fragment的实例。
    ?
    代码片段,双击复制
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    public class ScreenSlidePageFragment extends Fragment {
      
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            ViewGroup rootView = (ViewGroup) inflater.inflate(
                    R.layout.fragment_screen_slide_page, container, false);
      
            return rootView;
        }
    }


    添加一个ViewPager

    ViewPager在页面切换的时候设有内置的滑动手势,它能够默认展示屏幕动画。ViewPager使
    用PagerAdapter显示新的页面,所以PagerAdapter将会使用你之前创建的fragment类。
    开始时,先创建一个包含ViewPager的布局文件:
    ?
    代码片段,双击复制
    01
    02
    03
    04
    05
    <android.support.v4.view.ViewPager
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/pager"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />

    创建一个activity做下面的事情:
    1.将有ViewPager的布局设置为content view。
    2.创建一个继承于FragmentStatePagerAdapter抽象类的子类,实现getItem()方法提供一个
    ScreenSlidePageFragment的实例作为新的页面。该adapter也需要你实现getCount()方法,
    它会返回在adapter中创建的页面的数量。
    3.将PagerAdapter配置到ViewPager。
    4.重写设备的back键,使viewpager退回到前一个fragment。如果用户已经在第一个页面,则
    返回前一个activity。
    ?
    代码片段,双击复制
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    public class ScreenSlidePagerActivity extends FragmentActivity {
        /**
         * The number of pages (wizard steps) to show in this demo.
         */
        private static final int NUM_PAGES = 5;
      
        /**
         * The pager widget, which handles animation and allows swiping horizontally to access previous
         * and next wizard steps.
         */
        private ViewPager mPager;
      
        /**
         * The pager adapter, which provides the pages to the view pager widget.
         */
        private PagerAdapter mPagerAdapter;
      
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_screen_slide_pager);
      
            // Instantiate a ViewPager and a PagerAdapter.
            mPager = (ViewPager) findViewById(R.id.pager);
            mPagerAdapter = new ScreenSlidePagerAdapter(getFragmentManager());
            mPager.setAdapter(mPagerAdapter);
        }
      
        @Override
        public void onBackPressed() {
            if (mPager.getCurrentItem() == 0) {
                // If the user is currently looking at the first step, allow the system to handle the
                // Back button. This calls finish() on this activity and pops the back stack.
                super.onBackPressed();
            } else {
                // Otherwise, select the previous step.
                mPager.setCurrentItem(mPager.getCurrentItem() - 1);
            }
        }
      
        /**
         * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
         * sequence.
         */
        private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
            public ScreenSlidePagerAdapter(FragmentManager fm) {
                super(fm);
            }
      
            @Override
            public Fragment getItem(int position) {
                return new ScreenSlidePageFragment();
            }
      
            @Override
            public int getCount() {
                return NUM_PAGES;
            }
        }
    }


    使用PageTransformer定制动画

    要显示一个不同于默认动动画的动画,实现ViewPager.PageTransformer接口,并将其提供给
    view pager。该接口提供了唯一一个方法transformPage()。在每一个屏幕变换的点,该方
    法都被每一个可见的页面和每一个相邻退出屏幕的页面调用。例如,如果第三个页面是可见
    的,用户拖动屏幕滑向第四个界面,transformPage()被两个页面调用,第三个和第四个页
    面,在用户手势的每一步。

    在你的transformPage()的实现中,你可以通过基于当前页面的位置确定哪个页面将要被显
    示,来创建定制的动画,当前页面的位置可由transformPage()的参数确定。

    该位置参数明确了相对屏幕中心位置的页面。这是一个动态变化的参数,随着用户滑动屏幕
    而变化。当一个页面充满整个屏幕时,它的位置是0.当一个页面从屏幕的右侧退出时,其位
    置为1.如果用户滑动到第一页和第二页的中间时,第一页的位置为-0.5,第二页的位置为0.5。
    基于在屏幕上页面的位置,你可以通过使用setAlpha ( ) , setTranslationX ( ) ,或
    setScaleY ()方法设置页面属性,来创建自定义动画。

    当你有一个PageTransformer的实现时,调用setPageTransformer()方法来提供自定义的动
    画。
    ?
    代码片段,双击复制
    01
    02
    03
    ViewPager pager = (ViewPager) findViewById(R.id.pager);
     ...
     pager.setPageTransformer(true, new ZoomOutPageTransformer());


    Zoom-out页面变换

    ?
    代码片段,双击复制
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
        private static float MIN_SCALE = 0.85f;
        private static float MIN_ALPHA = 0.5f;
      
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            int pageHeight = view.getHeight();
      
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
      
            } else if (position <= 1) { // [-1,1]
                // Modify the default slide transition to shrink the page as well
                float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
                float vertMargin = pageHeight * (1 - scaleFactor) / 2;
                float horzMargin = pageWidth * (1 - scaleFactor) / 2;
                if (position < 0) {
                    view.setTranslationX(horzMargin - vertMargin / 2);
                } else {
                    view.setTranslationX(-horzMargin + vertMargin / 2);
                }
      
                // Scale the page down (between MIN_SCALE and 1)
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
      
                // Fade the page relative to its size.
                view.setAlpha(MIN_ALPHA +
                        (scaleFactor - MIN_SCALE) /
                        (1 - MIN_SCALE) * (1 - MIN_ALPHA));
      
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }


    深度页面变换

    ?
    代码片段,双击复制
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    public class DepthPageTransformer implements ViewPager.PageTransformer {
        private static float MIN_SCALE = 0.75f;
      
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
      
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
      
            } else if (position <= 0) { // [-1,0]
                // Use the default slide transition when moving to the left page
                view.setAlpha(1);
                view.setTranslationX(0);
                view.setScaleX(1);
                view.setScaleY(1);
      
            } else if (position <= 1) { // (0,1]
                // Fade the page out.
                view.setAlpha(1 - position);
      
                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);
      
                // Scale the page down (between MIN_SCALE and 1)
                float scaleFactor = MIN_SCALE
                        + (1 - MIN_SCALE) * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
      
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }
    展开全文
  • ViewPager+Fragment+PageTransformer实现多种动画效果,自己还可以进行扩展实现更多效果,只是提供思路
  • 最近需要做幻灯片效果,仔细想想其实就是viewpage的自动切换而已,于是想到了viewpager.pagertransformer来实现,使用方法很简单,网上也一大把,这里不做记录,仅仅记录下自己用到的自定义pagertransfomer,以后...

               最近需要做幻灯片效果,仔细想想其实就是viewpage的自动切换而已,于是想到了viewpager.pagertransformer来实现,使用方法很简单,网上也一大把,这里不做记录,仅仅记录下自己用到的自定义pagertransfomer,以后如果用到可以直接用。

    1.旋转动画

    public class RotateDownPageTransformer implements ViewPager.PageTransformer {
        private static final float ROT_MAX = 360.0f;
        private float mRot;
    
    
        public void transformPage(View view, float position) {
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setRotation(0);
    
            } else if (position <= 1) // a页滑动至b页 ; a页从 0.0 ~ -1 ;b页从1 ~ 0.0
            { // [-1,1]
                // Modify the default slide transition to shrink the page as well
                if (position < 0) {
    
                    mRot = (ROT_MAX * position);
                    view.setPivotX(view.getMeasuredWidth() * 0.5f);
                    view.setPivotY(view.getMeasuredHeight() * 0.5f);
                    view.setRotation(mRot);
                    view.setAlpha(1 + position);
                    view.setTranslationX(-view.getWidth()*position);
                } else {
                    view.setAlpha(1 - position);
                    view.setTranslationX(-view.getWidth()*position);
                    mRot = (ROT_MAX * position);
                    view.setPivotX(view.getMeasuredWidth() * 0.5f);
                    view.setPivotY(view.getMeasuredHeight() * 0.5f);
                    view.setRotation(mRot);
                }
    
                // Scale the page down (between MIN_SCALE and 1)
    
                // Fade the page relative to its size.
    
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setRotation(0);
            }
        }
    2.官方的缩放隐藏效果

    public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.85f;
        private static final float MIN_ALPHA = 0.5f;
    
        @SuppressLint("NewApi")
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            int pageHeight = view.getHeight();
    
    
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
    
            } else if (position <= 1) { //a页滑动至b页 ; a页从 0.0 -1 ;b页从1 ~ 0.0
                // [-1,1]
                // Modify the default slide transition to shrink the page as well
                float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
                float vertMargin = pageHeight * (1 - scaleFactor) / 2;
                float horzMargin = pageWidth * (1 - scaleFactor) / 2;
                if (position < 0) {
                    view.setTranslationX(horzMargin - vertMargin / 2);
                } else {
                    view.setTranslationX(-horzMargin + vertMargin / 2);
                }
    
                // Scale the page down (between MIN_SCALE and 1)
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
    
                // Fade the page relative to its size.
                view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE)
                        / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
    
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }

    3.延着Y轴进行旋转(可以自己修改成X轴)

    public class RotateCenterYPagerTransformer implements ViewPager.PageTransformer {
        private static final int MAX_ROTATE = 180;
    
        @Override
        public void transformPage(View view, float position) {
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 0) { // [-1,0]  控制左边view的   静止时他就是当前view
                if (position < -0.5) {
                    view.setAlpha(0);
                } else {
                    view.setAlpha(1);
                }
                if (position == 0) {
                    view.setRotationY(0);
                } else {
                    view.setRotationY(MAX_ROTATE * position);
                }
                view.setTranslationX(-view.getWidth() * position);
            } else if (position <= 1) { // (0,1]   1---0.5不出现
                if (position >= 0.5) {
                    view.setTranslationX(view.getWidth() * position);
                    view.setAlpha(0);
                } else {
                    view.setTranslationX(-view.getWidth() * position);
                    view.setAlpha(1);
                }
                view.setRotationY(MAX_ROTATE * position);
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    4.立体空间旋转缩放

    public class DepthScaleRotatePagerTransformer implements ViewPager.PageTransformer {
        private static final int MAX_ROTATE = 180;
    
        @Override
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 0) { // [-1,0]  控制左边view的   静止时他就是当前view
                // Use the default slide transition when moving to the left page
                view.setRotationY(MAX_ROTATE * position);
                view.setPivotX(pageWidth / 2);
                view.setPivotY(view.getHeight() / 2);
                if (position > -0.5) {
                    view.setTranslationX(0);
                    view.setScaleX(1 + position);
                    view.setScaleY(1 + position);
                    view.setAlpha(1 + position);
                } else if (position == -1.0) {
                    view.setTranslationX(0);
                    view.setScaleX(1);
                    view.setScaleY(1);
                    view.setAlpha(1);
                } else {
                    view.setScaleX(-position - 0.3f);
                    view.setScaleY(-position - 0.3f);
                    view.setTranslationX(-pageWidth * (position + 0.5f) * 2);
                    view.setAlpha(1 + position);
                }
            } else if (position <= 1) { // (0,1]
                view.setPivotX(pageWidth / 2);
                view.setPivotY(view.getHeight() / 2);
                view.setRotationY(MAX_ROTATE * position);
                if (position == 1.0f) {
                    view.setTranslationX(0);
                    view.setScaleX(1);
                    view.setScaleY(1);
                    view.setAlpha(1);
                } else if (position > 0.5) {//开始滑动
                    view.setTranslationX(-pageWidth * (position - 0.5f) * 2);
                    view.setScaleX(position - 0.3f);
                    view.setScaleY(position - 0.3f);
                    view.setAlpha(1 - position);
                } else {
                    view.setTranslationX(0);
                    view.setScaleX(1 - position);
                    view.setScaleY(1 - position);
                    view.setAlpha(1 - position);
                }
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }
    

    5.

    public class DepthPageTransformer implements ViewPager.PageTransformer {
        private static final float MIN_SCALE = 0.75f;
    
        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 0) { // [-1,0]  控制左边view的   静止时他就是当前view
                // Use the default slide transition when moving to the left page
                view.setAlpha(1);
    //            view.setTranslationX(pageWidth*position);
                view.setTranslationX(0);
                view.setScaleX(1);
                view.setScaleY(1);
    
            } else if (position <= 1) { // (0,1]
    //            // Fade the page out.
    //            Log.e("TAG", "transformPage: " + position);
                view.setAlpha(1 - position);
    
                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);
    
                // Scale the page down (between MIN_SCALE and 1)
                float scaleFactor = MIN_SCALE
                        + (1 - MIN_SCALE) * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }
    
    6.改变透明度

    public class AlphaChangeTransformer implements ViewPager.PageTransformer {
        @Override
        public void transformPage(View view, float position) {
            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);
            } else if (position <= 0) { // [-1,0]  控制左边view的   静止时他就是当前view
                view.setAlpha(1 + position);
                view.setTranslationX(-view.getWidth()*position);
            } else if (position <= 1) { // (0,1]
                view.setAlpha(1 - position);
                view.setTranslationX(-view.getWidth()*position);
            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    7.

    @TargetApi(18)
    public class TransPageTransformer implements ViewPager.PageTransformer {
        @Override
        public void transformPage(View view, float position) {
            int width = view.getWidth();
            int height = view.getHeight();
            if (position < -1) { // [-Infinity,-1)
                view.setTranslationX(0);
            } else if (position <= 0) { // [-1,0]  控制左边view的   静止时他就是当前view
                if (position == -1.0f) {
                    view.setTranslationX(0);
                } else {
                    view.setTranslationX(-width * position);
                    Rect rect = new Rect(0, 0, (int) (width * (1 + position)), height);
                    view.setClipBounds(rect);
                }
            } else if (position <= 1) { // (0,1]
                if (position == 1.0f) {
                    view.setTranslationX(0);
                } else {
                    view.setTranslationX(-width * position);
                    Rect rect = new Rect((int) (width * position), 0, width, height);
                    view.setClipBounds(rect);
                }
            } else { // (1,+Infinity]
                view.setTranslationX(0);
            }
        }
    }


    另外记录一下改变自动轮播的速度的方法:

    private void setViewPagerScrollSpeed(ViewPager viewPager, int speed) {
            try {
                Field field = ViewPager.class.getDeclaredField("mScroller");
                field.setAccessible(true);
                ViewPagerScroller viewPagerScroller = new ViewPagerScroller(viewPager.getContext(), new LinearInterpolator());
                field.set(viewPager, viewPagerScroller);
                viewPagerScroller.setDuration(speed);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    public class ViewPagerScroller extends Scroller {
        private int mDuration;
    
        public ViewPagerScroller(Context context) {
            super(context);
        }
    
        public ViewPagerScroller(Context context, Interpolator interpolator) {
            super(context, interpolator);
        }
    
        public void setDuration(int mDuration) {
            this.mDuration = mDuration;
        }
    
        @Override
        public void startScroll(int startX, int startY, int dx, int dy) {
            super.startScroll(startX, startY, dx, dy, this.mDuration);
        }
    
        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            super.startScroll(startX, startY, dx, dy, this.mDuration);
        }
    
    }




    展开全文
  • 我将其用在了APP的引导页面上,这个效果虽然看上去很难,但实际上实现起来特别的简单,主要是使用PageTransformer实现这个效果,推荐先看一下hongyang的前置教程:Android 自定义 ViewPager 打造千变万化的图片切换...

    (一) 开始

    ViewPager实现一个层叠的卡片,先看看效果

    层叠卡片

    我将其用在了APP的引导页面上,这个效果虽然看上去很难,但实际上实现起来特别的简单,主要是使用PageTransformer来实现这个效果,推荐先看一下hongyang的前置教程:Android 自定义 ViewPager 打造千变万化的图片切换效果,请确保你已经掌握前置,原理里都写了,就不在累述.(主要还是因为太懒了)

    (二) 编码

    1. 首先我们先创建一个Activity,配置好页面,就像以下效果。一个ViewPager,里面放fragment,fragment里面就放一个CardView。还需要给viewpager的setOffscreenPageLimit一个大一点的值。

    正常情况下,viewpager里面的内容是水平排列的。现在要做的第一步,就是将viewpager里面所有的view都显示在同一个位置,那么就需要自定义PageTransformer了。

    2. 自定义PageTransformer

    既然ViewPager里面的View是水平排列的,那么只要将每个view的x轴坐标更改为:view的宽度乘以下标的负数,这样就排列在一起了,为了方便起见,还给view增加了一个透明度。代码如下:

        public void transformPage(View page, float position) {
            //设置透明度
            page.setAlpha(0.5f);
            //设置每个View在中间
            page.setTranslationX((-page.getWidth() * position));
    
    }
    

    来看看效果吧。


    果然不出所料,效果和我们猜想的一样。

    3.看到这里,你是否已经想到接下来该怎么了做了吧?是的,我们只需要根据下标,将view按照顺序进行xy轴缩放,并且将Y轴向下移动。我定义了一个变量mOffset表示偏移量,赋值为40px。代码如下

        page.setTranslationX((-page.getWidth() * position));
        //缩放比例
        float scale = (page.getWidth() - mOffset * position) / (float) (page.getWidth());
    
    page.setScaleX(scale);
    page.setScaleY(scale);
    
    page.setTranslationY(mOffset * position);
    

    当当当当。。。下面就是见证奇迹的时刻了

    是不是完全达到了我们的预期呢?然而还没有结束,因为我不管怎么滑动都是没有效果,这是为什么呢?因为没有处理划出去的那一页,加了一个下标判断,position<= 0的情况下就是在翻页(打log),接下来看代码:

        public void transformPage(View page, float position) {
        if (position <= 0.0f) {//被滑动的那页
            page.setTranslationX(0f);
        } else {//未被滑动的页
            page.setTranslationX((-page.getWidth() * position));
            //缩放比例
            float scale = (page.getWidth() - mOffset * position) / (float) (page.getWidth());
    
        page.setScaleX(scale);
        page.setScaleY(scale);
    
        page.setTranslationY(mOffset * position);
    
    }
    

    }

    来看看效果:


    4.至此,也是差不多实现了效果,还差最后一步。

    第一张效果图中,在翻页的时候有一个旋转的角度,而我们前面实现的只是一个平滑的效果。在这里达到的效果就是从0°开始,随着翻页的进行,卡片旋转至-45°角,从上一步得到一个结论:position<= 0的情况下就是在翻页。看代码:

    public void transformPage(View page, float position) {
        if (position <= 0.0f) {//被滑动的那页
            page.setTranslationX(0f);
            //旋转角度  45° * -0.1 = -4.5°
            page.setRotation((45 * position));
        } else {
            //缩放比例
            float scale = (page.getWidth() - mScaleOffset * position) / (float) (page.getWidth());
    
        page.setScaleX(scale);
        page.setScaleY(scale);
    
        page.setTranslationX((-page.getWidth() * position));
        page.setTranslationY((mScaleOffset * <span class="hljs-number">0.8f</span>) * position);
    }
    

    }

    运行起来看看效果

    效果虽然是达到了,但是为什么会留一个角呢?想必聪明的你应该想明白了吧?里面的view移动的是一个屏幕的宽度,当我们平移的时候刚好移动到了屏幕的外面,当然没有问题。但是旋转却是以中心为原点进行喜欢转的,所以自然,就会漏出一个角了。
    解决方法是view进行旋转的同时,将view的X轴进行减少,减少多少呢?从上图看,大概⅓就差不多能够移动到屏幕外面了。
    上代码:

    public void transformPage(View page, float position) {
        if (position <= 0.0f) {//被滑动的那页  position 是-下标~ 0
            page.setTranslationX(0f);
            //旋转角度  45° * -0.1 = -4.5°
            page.setRotation((45 * position));
            //X轴偏移 li:  300/3 * -0.1 = -10
            page.setTranslationX((page.getWidth() / 3 * position));
        } else {
            //缩放比例
            float scale = (page.getWidth() - mScaleOffset * position) / (float) (page.getWidth());
    
        page.setScaleX(scale);
        page.setScaleY(scale);
    
        page.setTranslationX((-page.getWidth() * position));
        page.setTranslationY((mScaleOffset * <span class="hljs-number">0.8f</span>) * position);
    }
    

    }

    看看,效果是不是更加的细腻了呢?

    至此,整个效果就算是完成了,下面附上PageTransformer的代码

    /**
     * 水平滑动的
     */
    public class CardPageTransformer implements ViewPager.PageTransformer {
        /**
         * 偏移量
         */
        private int mScaleOffset = 40;
    
    <span class="hljs-comment">/**
     * <span class="hljs-doctag">@param</span> mScaleOffset 缩放偏移量 单位 px
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CardPageTransformer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> mScaleOffset)</span> </span>{
        <span class="hljs-keyword">this</span>.mScaleOffset = mScaleOffset;
    }
    
    <span class="hljs-meta">@SuppressLint</span>(<span class="hljs-string">"NewApi"</span>)
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">transformPage</span><span class="hljs-params">(View page, <span class="hljs-keyword">float</span> position)</span> </span>{
        <span class="hljs-keyword">if</span> (position &lt;= <span class="hljs-number">0.0f</span>) {<span class="hljs-comment">//被滑动的那页  position 是-下标~ 0</span>
            page.setTranslationX(<span class="hljs-number">0f</span>);
            <span class="hljs-comment">//旋转角度  45° * -0.1 = -4.5°</span>
            page.setRotation((<span class="hljs-number">45</span> * position));
            <span class="hljs-comment">//X轴偏移 li:  300/3 * -0.1 = -10</span>
            page.setTranslationX((page.getWidth() / <span class="hljs-number">3</span> * position));
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">//缩放比例</span>
            <span class="hljs-keyword">float</span> scale = (page.getWidth() - mScaleOffset * position) / (<span class="hljs-keyword">float</span>) (page.getWidth());
    
            page.setScaleX(scale);
            page.setScaleY(scale);
    
            page.setTranslationX((-page.getWidth() * position));
            page.setTranslationY((mScaleOffset * <span class="hljs-number">0.8f</span>) * position);
        }
    
    }
    

    }

    (三) 展望

    上面的步骤有没有引起你的联想呢?例如:层叠在上面、左面、右面、上下滑动,再加个透明动画?哈哈 这些我都实现了,你可以直接引用我的library,使用我里面已经写好的PageTransformer。

    来先看看效果


    以下是使用方法

    setp 1

    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
    

    step 2

    dependencies {
            compile 'com.github.aohanyao:ViewPagerCardTransformer:v1.0'
    }
    

    step 3

     vpMain.setPageTransformer(true, CardPageTransformer.getBuild()//建造者模式
                .addAnimationType(PageTransformerConfig.ROTATION)//默认动画 default animation rotation  旋转  当然 也可以一次性添加两个  后续会增加更多动画
                .setRotation(-45)//旋转角度
                .addAnimationType(PageTransformerConfig.ALPHA)//默认动画 透明度 暂时还有问题
                .setViewType(mViewType)
                .setOnPageTransformerListener(new OnPageTransformerListener() {
                    @Override
                    public void onPageTransformerListener(View page, float position) {
                        //你也可以在这里对 page 实行自定义动画 cust anim
                    }
                })
                .setTranslationOffset(40)
                .setScaleOffset(80)
                .create());
    

    about

    如果文中有什么不对的地方,欢迎指出!

    源码地址 如果我的代码对你有帮组,请给我一个star

    我的简书

    来来扫下码,关注一下吧,或者微信搜索AndroidRookie

    AndroidRookie
    转自:https://www.jianshu.com/p/1cb7cd31fa65
    展开全文
  • 技术这东西就是需要日积月累的,每天学习一...今天复习一个小知识点,就是用ViewPager+Fragment+PageTransformer实现滑动动画,很简单,最后我会将源码demo下载地址附上,高手略过啊。 首先我们来看一下第一个效果:
  • 1、介绍如何使用setPageTransformer设置切换动画;...2、自定义PageTransformer实现个性的切换动画; 3、该方法在SDK11以下的版本不起作用,我们会对其做一定修改,让其向下兼容。 官方示例地址:
  • 主要介绍了Android使用自定义PageTransformer实现个性的ViewPager切换动画,具有很好的参考价值,一起跟随小编过来看看吧
  • 本文没有提供酷炫的动画实现,而是分析理解如何使用自定义PageTransformer完成要想的效果。1、PageTransformer之position分析 从3.0开始,ViewPager开始支持自定义切换动画,官方提供的接口为PageTransformer,因此...
  • 我们要实现如下的效果,ViewPager正中的page显示为绿色,其余两边的显示为蓝色。中间page像左右两边切换时会从绿色慢慢过渡到蓝色,同理两边的page向中间切换时颜色也会慢慢过渡,而不是直接跳变。 PageTransformer...
  • 利用给自定义PageTransformer,给viewpager设置不同的切换特效,多种特效的欢迎页面
  • package com.example.test; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.View; ... * Created by mengjianbo on 2018-08-07. ...public class TransFormer impl...
  • SeniorUI_高级UI汇总目录 一 PageTransformer * @param reverseDrawingOrder true if the supplied PageTransformer requires page views * to be drawn from last to first instead ...
  • 学习了一下PageTransformer,这个类在ViewPager页面滚动时被调用,适用于ViewPager中的itemview有动画的场景。下面是API中关于PageTransformer的介绍 A PageTransformer is invoked whenever a visible/attached ...
  • 本文实现了ViewPager利用PageTransformer实现的动画效果 使用很简单,mViewPager.setPageTransformer()设置就可以,只需要实现PageTransformer,重写void transformPage(View page, float position) ,看看position...
  • 使用viewpager的PageTransformer实现的视差效果源码.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
1 2 3 4 5 ... 20
收藏数 1,230
精华内容 492
关键字:

pagetransformer实现