pagetransformer 速度_pagetransformer - CSDN
精华内容
参与话题
  • 一,PageTransformer 的简单介绍 从Android 3.0开始,ViewPager提供了PageTransformer接口来帮助应用方便实现各种切换效果,该接口是在ViewPager滑动的时候被调用的,下面是其定义:/** * A PageTransformer is ...

    一,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

    展开全文
  • ViewPager动画详解

    千次阅读 2015-01-12 10:19:51
    animations with PageTransformer以及农民伯伯分享的Create ViewPager transitions 文章,都是通过ViewPager来实现酷炫的动画,而现在的App中ViewPager的动画使用也非常的广泛。正好最近一直研究动画,那么就...

    GitHub:lightSky

    微博:    light_sky , 即时分享最新技术,欢迎关注


    前言

    前两天看到鲍永章分享的Great animations with PageTransformer以及农民伯伯分享的Create ViewPager transitions 文章,都是通过ViewPager来实现酷炫的动画,而现在的App中ViewPager的动画使用也非常的广泛。正好最近一直研究动画,那么就趁热打铁,分析一下相关的开源库吧。本篇文章介绍的ViewPager动画,可以分为两类,第一类是针对于ViewPager的界面滑动动画(这个是PageTransformer的真正用途),分析并比较了AndroidImageSlider和JazzyViewPager两种实现,第二类是对ViewPager中的内容进行动画处理,这个是这个是PageTransformer的巧妙应用,处理好了可以达到很棒的交互效果,示例是Yahoo天气的视差效果。


    ViewPager动画的实现原理

    从3.0开始,ViewPager开始支持自定义切换动画,暴露的接口为PageTransformer,因此只要实现PageTransformer接口和其唯一的方法transformPage(View view, float position)即可。

    /**
       * 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);
     }

    • 参数position
      给定界面的位置相对于屏幕中心的偏移量。在用户滑动界面的时候,是动态变化的。那么我们可以将position的值应用于setAlpha(), setTranslationX(), or setScaleY()方法,从而实现自定义的动画效果。
      另外在ViewPager滑动时,内存中存活的Page都会执行transformPage方法,在滑动过程中涉及到两个Page,当前页和下一页,而它们的position值是相反的(因为是相对运动,一个滑入一个滑出),比如,页面A向右滑动到屏幕一半,页面B也正好处于一半的位置,那么A和B的position为:0.5 和 -0.5
      position == 0 :当前界面位于屏幕中心的时候
      position == 1 :当前Page刚好滑出屏幕右侧
      position == -1 :当前Page刚好滑出屏幕左侧


    AndroidImageSlider动画库解析

    要说到动画库,肯定会想到代码家,没错,代码家也开源了一个ViewPager效果的库:AndroidImageSlider ,我们就来分析下这个库的实现。AndroidImageSlider除了基本的page动画外,也支持用户为Page内容添加自定义的动画,比如下面描述框的动画。


    AndroidImageSlider兼容性的实现原理
    因为API 11才开始支持PagerTransformer. 这里面修改了Android系统的ViewPager,名为ViewPagerEx,ViewPager里面有一段if逻辑判断是否在3.0以上使用PagerTransformer。因为PagerTransformer动画效果的实现依赖了PropertyViewAnim。但代码家的这个库使用NineOldAndroids实现了向3.0之前的兼容。因此就把这个if条件去掉了,其它部分都没变。

    /**
     * @author daimajia : I just remove the if condition in setPageTransformer() to make it compatiable with Android 2.0+
     * of course, with the help of the NineOldDroid.
     * Thanks to JakeWharton.
     * http://github.com/JakeWharton/NineOldAndroids
     */


    AndroidImageSlider的总体设计

    • BaseTransformer
      所有Transformer的基类,实现了ViewPagerEx.PageTransformer接口以及transformPage方法,并提供了onPreTransform(View view, float position)、onPostTransform(View view, float position)、onTransform(View view, float position);
      分别在transformPage前后调用,用来处理为每一次的执行动画前的准备和结束动作,比如还原所有的动画状态。

    • BaseAnimationInterface:
      ViewPagerEx执行Transformer动画的时候注入一些自己的动画。你需要实现该接口,然后实现以下4个方法,获取SlideView中的View,实现自己的动画。比如底部的DescriptionText动画DescriptionAnimation 出现时的动画就是onNextItemAppear中添加的,你可以点入,看下源码
      onPrepareCurrentItemLeaveScreen(View current)
      onPrepareNextItemShowInScreen(View next)
      onCurrentItemDisappear(View view)
      onNextItemAppear(View view)

    而这4个方法的调用是在BaseTransformer中。BaseTransformer统一管理了Page滑动时的所有动画。为了获取这4个方法的调用时机,也是煞费苦心啊,先说下思路:
    因为ViewPager滑动的时候transformPage方法是实时调用的,这里获取最初两次调用时传入的position进行比较。通过一个HashMap<view, arraylist>来维护不同pageView的多个position。但这里为了优化,只取前两个position做比较。
    先判断起始滑动的方向,然后再判断下一次滑动的方向,两次结果作差来判断到底哪个page要离开界面还是进入界面。

    确定2个界面的4种临界状态

    if(mCustomAnimationInterface != null){
                if(h.containsKey(view) == false || h.get(view).size() == 1){
                    if(position > -1 && position < 1){
                        if(h.get(view) == null){
                            h.put(view,new ArrayList<Float>());//为每个View创建一个List,来存储偏移分数position
                        }
                        h.get(view).add(position);//向指定的View中添加偏移分数
                        if(h.get(view).size() == 2){
                            float zero = h.get(view).get(0);
                            float cha = h.get(view).get(1) - h.get(view).get(0);//当前滑动的位移偏移量分数差: newfraction - oldfraction
                            if(zero > 0){//起始时,向左滑动,当前Page中心位于屏幕中心左侧
                                //判断滑动趋势,如果继续向左侧滑动,position从0到1越来越大 newfraction > oldfraction
                                if(cha > -1 && cha < 0){//向右侧滑动
                                    //in
                                    mCustomAnimationInterface.onPrepareNextItemShowInScreen(view);//下一个Page将要进入屏幕
                                }else{//cha > 0 继续向左侧滑动
                                    //out
                                    mCustomAnimationInterface.onPrepareCurrentItemLeaveScreen(view);//当前Page将要离开屏幕
                                }
                            }else{//起始时,向右滑动,当前Page中心位于屏幕中心右侧
                                //判断滑动趋势,如果继续向右侧滑动,position从0到-1越来越小 newfraction < oldfraction
                                if(cha > -1 && cha < 0){//负值,继续向右滑动,因此当前page将要滑出屏幕
                                    //out
                                    mCustomAnimationInterface.onPrepareCurrentItemLeaveScreen(view);//当前Page将要离开屏幕
                                }else{//向左滑动
                                    //in
                                    mCustomAnimationInterface.onPrepareNextItemShowInScreen(view);//下一个Page将要离开屏幕
                                }
                            }
                        }
                    }
                }
            }
     boolean isApp,isDis;
        /**
         * Called each {@link #transformPage(View, float)} call after {@link #onTransform(View, float)} is finished.
         *
         * @param view
         * @param position
         */
        protected void onPostTransform(View view, float position) {
            if(mCustomAnimationInterface != null){
                if(position == -1 || position == 1){//当前界面刚好完全移除界面
                    mCustomAnimationInterface.onCurrentItemDisappear(view);
                    isApp = true;
                }else if(position == 0){
                    mCustomAnimationInterface.onNextItemAppear(view);//下一个Page刚好完全显示
                    isDis = true;
                }
                if(isApp && isDis){
                    h.clear();
                    isApp = false;
                    isDis = false;
                }
            }
        }

    • BaseSliderView
      该类就是SlideView的基类,持有SlideView的一些公共方法,比如设置SliderView的image资源的方法image(File file),图片加载异常和失败的处理,empty(URL)用于展示,errorDisappear(boolean disappear)。这种思想和一个EmptyView有些类似,在我公司的项目也是使用了这种方式,比如通常一个ListView的界面,会有一个包装后的progressbar(包含各种情况的处理)来显示进度,当加载失败的时候,或者无数据的时候,可以调用该progressbar身上的方法,去决定显示何种布局。使用起来很方便。当然如果你的SliderView更复杂,你可以通过实现BaseSliderView,然后实现自己的SliderView。

    下面两个类就是切换的View:
    DefaultSliderView:实现了BaseSliderView,该View默认就是一张图片
    TextSliderView:带有图片和描述性文字的View

    • Sliderlayout:
      一个控制中心,将InfiniteViewPager,PageIndicator,粘合在一起,控制动画的样式,ViewPager轮循的播放。

    addSlider:向ViewPager中添加一个SlideView
    startAutoCycle:启动轮播
    pauseAutoCycle:停止轮播
    setDuration: 轮播间隔
    setPagerTransformer 为ViewPager设置自定义的PageTransformer
    onInterceptTouchEvent 在用户手势按下的时候,就停止轮循

    Note:
    这里在onInterceptTouchEvent中处理而不能再onTouchEvent中处理。因为SlideView会消费掉点击事件,事件被消费了,没法返回给SlideLayout的onTouchEvent中。

    OK,总体设计弄清楚后,剩下来就是动画中最核心的部分了,就是动画效果的实现,这里只简单的介绍Accordion动画的实现,其它的大家可以自己分析。关于PropertyView动画的使用,可以参考我的另一篇文章:PropertyAnim实际应用

    Accordion

    public class AccordionTransformer extends BaseTransformer {
        @Override
        protected void onTransform(View view, float position) {
            ViewHelper.setPivotX(view,position < 0 ? 0 : view.getWidth());
            ViewHelper.setScaleX(view,position < 0 ? 1f + position : 1f - position);
        }
    }

    代码家在README中注明了Thanks JazzyViewPager,开始没注意,后来看JazzyViewPager的源码时候偶然发现AndroidImageSlider的一些实现的灵感是来自JazzyViewPager项目。不过JazzyViewPager的实现方式略显复杂,没有使用PageTransformer接口,而是使用了OnPageChangeListener接口的onPageScrolled方法。
    下面简单的看下JazzyViewPager库的动画实现,它将positionOffset作为参数控制。由于positionOffset的值为[0,1),所以就需要分别处理正负的情况。另外JazzyViewPager是通过维护一个LinkedHashMap来持有Page的引用。在Adapter添加界面的时候,会调用JazzyViewPager的 setObjectForPosition(Object obj, int position) 方法存入到集合中去。然后在onPageScrolled方法中再根据position获取当前Page的前一个mLeft和后一个mRight界面,分别对前后两个界面添加动画。

     

    两种方式的关键参数区别

    onPageScrolled(int position, float positionOffset, int positionOffsetPixels)方法的参数:

    /**
             * 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);

    下面是打印的PageTransformer接口的transformPage时position的值:相邻两界面的绝对值的和为1.而正负则表示了滑入和滑出状态

    12-15 21:03:13.025    I/System.out﹕ transformPage----------------------    -0.43611112
           12-15 21:03:13.025    I/System.out﹕ transformPage----------------------    0.5638889
           
    12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    -0.38055557
           12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    0.61944443
           
    12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    -0.37777779
           12-15 21:03:13.045    I/System.out﹕ transformPage----------------------    0.62222224
           
    12-15 21:03:13.055    I/System.out﹕ transformPage----------------------    -0.32916668
           12-15 21:03:13.055    I/System.out﹕ transformPage----------------------    0.67083335
           
    12-15 21:03:13.065    I/System.out﹕ transformPage----------------------    -0.32222223
           12-15 21:03:13.065    I/System.out﹕ transformPage----------------------    0.67777777
           
    12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    -0.27916667
           12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    0.72083336


    onPageScrolled方法的positionOffset的值为 [0, 1) ,而PageTransformer接口的transformPage(View page, float position) 已经标好了正负值(滑入和滑出),如果你的动画正好是相对的,那么用transfromPage就简单的多。

    我们取同一种动画效果Cube来比较一下JazzyViewPager和AndroidImageSlider两者的实现:

    JazzyViewPager部分源码

    	@Override
    	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    		
    		...
    		float effectOffset = isSmall(positionOffset) ? 0 : positionOffset;
    		mLeft = findViewFromObject(position);
    		mRight = findViewFromObject(position+1);
    		switch (mEffect) {
    			case Standard:
    				break;
    			...
    			case animateCube:
    				animateCube(mLeft, mRight, effectOffset);
    				break;
    		}
    	}
    	...
    	private void animateCube(View left, View right, float positionOffset, boolean in) {
    		if (mState != State.IDLE) {
    			if (left != null) {
    				manageLayer(left, true);
    				mRot = (in ? 90.0f : -90.0f) * positionOffset;
    				ViewHelper.setPivotX(left, left.getMeasuredWidth());
    				ViewHelper.setPivotY(left, left.getMeasuredHeight()*0.5f);
    				ViewHelper.setRotationY(left, mRot);
    			}
    			if (right != null) {
    				manageLayer(right, true);
    				mRot = -(in ? 90.0f : -90.0f) * (1-positionOffset);
    				ViewHelper.setPivotX(right, 0);
    				ViewHelper.setPivotY(right, right.getMeasuredHeight()*0.5f);
    				ViewHelper.setRotationY(right, mRot);
    			}
    		}
    	}
    	public void setObjectForPosition(Object obj, int position) {//每次Adapter实例化View的时候,调用该方法,将实例化的View存入集合
    			mObjs.put(Integer.valueOf(position), obj);
    		}
    	
    	public View findViewFromObject(int position) {//根据position从集合中获取到对应的View
    			Object o = mObjs.get(Integer.valueOf(position));
    			if (o == null) {
    				return null;
    			}
    			PagerAdapter a = getAdapter();
    			View v;
    			for (int i = 0; i < getChildCount(); i++) {
    				v = getChildAt(i);
    				if (a.isViewFromObject(v, o))
    					return v;
    			}
    			return null;
    		}
    	....
    }

    AndroidIamgeSlider中的CubeIn:

    public class CubeInTransformer extends BaseTransformer {
    	@Override
    	protected void onTransform(View view, float position) {
    		// Rotate the fragment on the left or right edge
            ViewHelper.setPivotX(view,position > 0 ? 0 : view.getWidth());
            ViewHelper.setPivotY(view,0);
            ViewHelper.setRotation(view,-90f * position);
    	}
    }

    JazzyViewPager:CubeIn上面代码中已经贴出:

    if (left != null) {
    	...
    	mRot = (in ? 90.0f : -90.0f) * positionOffset;
    	...
    	}
    if (right != null) {
    	mRot = -(in ? 90.0f : -90.0f) * (1-positionOffset);
    }

    可以精简为:

    positionOffset * value
    -(1-positionOffset) * value

    与从上面的transformPage打印的position的值再比较下

    12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    -0.27916667
           12-15 21:03:13.075    I/System.out﹕ transformPage----------------------    0.72083336


    结论:
    发现transformPage已经帮我们处理好了一切,直接用。我们可以根据正负符号来判断滑入和滑出的View(不用像JazzyViewPager那样去维护一个集合了),从而针对滑入滑出做出不同或相对的的动画。最简单的,两个界面如果是简单的相对动画(滑入对滑出),则什么都不用处理,直接用就行了,就像下面介绍的Yahoo视差的实现一样,具体可以看下面的讲解。

    大家仔细看下相同的动画效果的处理方式,CubeInTransformer不用单独处理上一个和下一个界面,而只管根据position的正负判断当前Page和下一个Page去自定义不同的动画即可。
    所以可以把AndroidImageSlider中的一些动画效果看做是JazzyViewPager的精简版本。

    对于ViewPager如何帮我们处理View的呢?可以看下源码:

     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的Page的滑动动画,两种实现方式:
    PageTransformer.transformPage方式:在执行onPageScrolled方法的时候,会遍历ViewPager的所有View,并执行其transformPage方法。position是已经处理好的(方向和值)
    onPageScrolled方式:略显复杂,因为没法拿到View,还要自己去维护一个View集合,并且positionOffset的限制,需要自己去处理不同View的position : PageA:position , PageB:-(1-position)。


    为ViewPager的Page内容添加动画,实现炫酷的交互效果

    Tholotis


    实现原理

    为Page内部的View处理不同的平移速度,达到视差的效果,作者的代码:

    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);
        }
    }

    GitHub上类似的效果
    https://github.com/prolificinteractive/ParallaxPager

    https://github.com/flavienlaurent/discrollview

    这两个项目都封装成了库,使用的时候也简单,但一般我们可以通过ViewPager.PageTransformer来实现这样的效果,从上面AndroidImageSlider与JazzyViewPager的对比中也能看到,PageTransformer的实现方式更简单。而且ViewPager的动画库也很多,比如上面的JazzyViewPager。你只需把某一个动画效果的transformPage方法的逻辑拿来就可用,当然如果你的需求更复杂,或者ViewPager实现起来较麻烦,你可以考虑上面的两个项目,扩展自己的思维。

    JazzyViewPager:
    https://github.com/jfeinstein10/JazzyViewPager/blob/master/lib/src/com/jfeinstein/jazzyviewpager/JazzyViewPager.java
    https://github.com/prolificinteractive/ParallaxPager
    https://github.com/flavienlaurent/discrollview


    Yahoo天气

    原理很简单,只是这次处理的动画对象是背景图片,减慢其平移的速度,而ViewPager的内容正常移动,从而达到视差的效果。

    public class ParallaxPageTransformer implements ViewPager.PageTransformer {
    	
    		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(1);
     
    		        } else if (position <= 1) { // [-1,1]
    		            
    		        	dummyImageView.setTranslationX(-position * (pageWidth / 2)); //Half the normal speed
    		            
    		        } else { // (1,+Infinity]
    		            // This page is way off-screen to the right.
    		            view.setAlpha(1);
    				}
    		    
     
    		}
    	}

    OK,本来想自己写,但刚巧在GitHub上发现了一个:ParallaxPagerTransformer ,并提供了APK ,实现了Yahoo天气的效果,但多了一些缩放的效果,将缩放的代码注释掉就和Yahoo天气的效果完全一样了。另外想clone到本地的朋友注意了,由于作者的AndroidStudio版本太老,导入的时候你需要做一些处理。
    作者把该Transformer抽取出来,做为了一个lib,就一个类,核心代码很简单,说明ViewPager.PageTransformer接口很强大啊:

    @Override
      public void transformPage(View view, float position) {
          View parallaxView = view.findViewById(id);
          if (parallaxView != null) {
              if (position > -1 && position < 1) {
                  float width = parallaxView.getWidth();
                  parallaxView.setTranslationX(-(position * width * speed));
                  float sc = ((float)view.getWidth() - border)/ view.getWidth();
                  if (position == 0) {//这里处理了缩放的效果,去掉即和Yahoo天气的效果一样
                      view.setScaleX(1);
                      view.setScaleY(1);
                  } else {
                      view.setScaleX(sc);
                      view.setScaleY(sc);
                  }
              }
          }
      }

    看了上面的实现,大家应该知道如何去实现类似的交互动画了,而且现在的App导航页中,也越来越多的使用到了这样的交互,作者在文章还列举了News Digest的导航页,有了思路,实现起来应该就不难了,第一、三页的动画上面已经介绍过,对于第二页,其实就是一个旋转动画。实时的旋转可以通过实时变化的position来处理。



    类似的项目
    https://github.com/andraskindler/parallaxviewpager


    总结:

    整篇文章介绍的东西其实很简单,只是以前没有研究过ViewPager.PageTransformer,使用简单,但功能强大,position参数在动画处理中相当重要,因为是实时的百分比,所以省去了自己不少计算,如果你需要为ViewPager自定义动画,那么选择PageTransformer,对于本文的第二类巧妙动画效果的介绍,看具体情况决定是否使用PageTransformer,如果position能很方便帮助动画的计算,那是最好的,如果不是那么你完全可以使用onPageScrolled来处理,源码中也可看到,PageTransformer就是在onPageScroll中调用的。
    使用时要注意,它只支持3.0以上的系统。如果要兼容,可以参考上面AndroidImageSlider的兼容实现。在文章中也插入了不少ViewPager动画项目的链接,也许不是使用PageTransformer,但也是一种思路的扩展,供大家参考。下一篇文章,我会介绍Fragment的动画,大家敬请期待。

    参考文献:
    官方文档
    Great animations with PageTransformer
    Create ViewPager transitions


    GitHub上相关的ViewPager动画的项目

    https://github.com/daimajia/AndroidImageSlider
    https://github.com/inovex/ViewPager3D

    轮循的ViewPager
    https://github.com/antonyt/InfiniteViewPager
    https://github.com/JakeWharton/salvage
    https://github.com/Trinea/android-auto-scroll-view-pager

    VerticalViewPager
    https://github.com/JakeWharton/Android-DirectionalViewPager
    https://github.com/LambergaR/VerticalViewPager
    https://github.com/VenomVendor/AutoNotifyViewPager

    https://github.com/Dreddik/AndroidTouchGallery

    特效的ViewPager
    https://github.com/kmshack/Android-ParallaxHeaderViewPager
    https://github.com/andraskindler/parallaxviewpager
    https://github.com/MoshDev/BackgroundViewPager

    与ViewPager一起使用的导航:
    https://github.com/astuetz/PagerSlidingTabStrip (不支持TextView颜色的变化)
    https://github.com/jpardogo/PagerSlidingTabStrip (支持TextView颜色变化)
    https://github.com/DSofter/SmoothTabIndicator

    FragmentAnim
    https://github.com/DesarrolloAntonio/FragmentTransactionExtended







    展开全文
  • 本篇介绍app欢迎页的一些动画效果(1)视差效果 是否看到每个view位置移动了、且移动速度不一致 (2)3D翻转 (2)放大缩小 一、 自定义动画说到欢迎页一定会想到ViewPager,动画设置自然想到ViewPager....

    本篇介绍app欢迎页的一些动画效果

    (1)视差效果 是否看到每个view位置移动了、且移动速度不一致
    这里写图片描述这里写图片描述

    (2)3D翻转
    这里写图片描述

    (2)放大缩小
    这里写图片描述

    一、 自定义动画

    说到欢迎页一定会想到ViewPager,动画设置自然想到ViewPager.setPageTransformer(boolean, PageTransformer) ,所以我们先自定义一个PageTransformer的子类WelcomePagerTransformer 来实现我们想要的动画效果

    public class WelcomePagerTransformer implements ViewPager.PageTransformer {
        @Override
        public void transformPage(View view, float position) {
            if (position < 1 && position > -1) {
                //拿到所有的View
                ViewGroup rlGroup = (ViewGroup) view.findViewById(R.id.rl_group);
                for (int i = 0; i < rlGroup.getChildCount(); i++) {
                    View child = rlGroup.getChildAt(i);
                    //设置视差效果,给当前的view来个加速度
                    float factor = (float) Math.random() * 2;
                    if (child.getTag() == null) {
                        child.setTag(factor);
                    } else {
                        factor = (float) child.getTag();
                    }
                    child.setTranslationX(position * factor * child.getWidth());
                }
                //放大缩小
    //            view.setScaleX(1-Math.abs(position));
    //            view.setScaleY(1-Math.abs(position));
    //            view.setScaleX(Math.max(0.9f,1-Math.abs(position)));
    //            view.setScaleY(Math.max(0.9f,1-Math.abs(position)));
                //3D翻转
    //            view.setPivotX(position < 0f ? view.getWidth() : 0f);
    //            view.setRotationY(position * 90f);
                //3D内翻转
    //            view.setPivotX(position < 0f ? view.getWidth() : 0f);
    //            view.setPivotY(view.getHeight()*0.5f);
    //            view.setRotationY(position * 60f);
                //偏移
    //            view.setTranslationX(position < 0 ? 0f : -view.getWidth() * position);
    
            }
    
        }
    }

    二、 设置动画

    在activity设置viewpage自定义的动画

     vpWelcome = (ViewPager)findViewById(R.id.vp_welcome);
     WelcomePagerTransformer welcomePagerTransformer = new WelcomePagerTransformer();
     vpWelcome.setPageTransformer(true,welcomePagerTransformer);

    接下来就是设置viewpage的适配器FragmentPagerAdapter跟平常的欢迎页的操作是一样的,该怎么写就怎么写!

    demo下载地址:https://github.com/972242736/WelcomeAnimation.git

    展开全文
  • 什么是视差滚动 视差滚动效果是怎样的 如何实现视差滚动效果 1 通过使用ViewPager实现页面的左右滑动 2 ViewPager有办法实现ParallaxScrolling吗 3 ViewPagerPageTransformer如何使用 由视差滚动效果引起的思考 ...

    1. 什么是视差滚动?

    Parallax Scrolling(视差滚动),是一种常见的动画效果。视差一词来源于天文学,但在日常生活中也有它的身影。在疾驰的动车上看风景时,会发现越是离得近的,相对运动速度越快,而远处的山川河流只是缓慢的移动着,这就是最常见的视差效果。视差动画独有的层次感能带来极为逼真的视觉体验,iOS、Android Launcher、Website都将视差动画作为提升用户视觉愉悦度的不二选择。
    视差滚动效果一般是指,ViewPager滑动时其中的内容元素滚动速率不一,形成的元素动画错位效果。APP第一次打开出现引导页也不是什么新鲜的事儿,ViewPager配上几张设计师精心绘制的图片,分分钟即可了事。但是总有人把平凡的事情做到不平凡,现在市场上的众多应用里都出现了视差动画的身影,随着用户手指的滑动,反馈以灵动、贴近真实的视觉以及操作体验,对应用的初始印象登时被提升到一个极高的点。

    2. 视差滚动效果是怎样的?

    这里写图片描述

    3. 如何实现视差滚动效果?

    1). 通过使用ViewPager实现页面的左右滑动

    相信大部分Android开发者对ViewPager控件并不陌生,它可以实现简单的页面左右滑动效果,包含在android-support-v4.jar兼容包中。其实使用ViewPager也可以实现简单的滑动引导页,但想要做到有视差滚动效果的话,可能要深挖一下ViewPager的API了。

    2). ViewPager有办法实现ParallaxScrolling吗?

    视差滚动效果,主要表现为内容元素滚动速率的差异上。比如在ViewPager中滑动了1px,而A元素移动2px,B元素移动1.5px,这种移动差距的比率,或称之为parallaxCofficient,即视差系数或者视差速率,正是同一个界面中的元素,由于层级不同,赋予的视差系数不同,在移动速度上的差异形成了视差的错觉,这就是我们要追求的效果。
    知道原理就好办了,使用ViewPager.OnPageChangeListener监听接口,实现onPageScrolled、onPageSelected、onPageScrollStateChanged三个方法,然后动态计算不就得了。
    NO!如果我们在这三个方法里面动态计算视差系数,又如何使这些值作用于页面的每个子View上面呢?难道要为每个子View设置一些translate动画?那什么时候该是第一个子View的动画开始呢?那么第二个呢?等等,这个方法明显不靠谱!那有什么更好的解决方案呢?
    所幸Android3.0以后为ViewPager准备好了变形接口ViewPager.PageTransformer,它提供了一个方法transformPage(View page, float position),正是为我们完成视差动画量身定制的。让我们来看看它的源码:

    /**
      * 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);
     }

    从源码中不难看到,PageTransformer在ViewPager滑动时被触发,它为我们自定义页面中进行视图变换打开了一扇大门。PagerTransformer的注释已经说明了它的用处——它给应用提供了一个为页面滑动设置自定义动画属性的机会。That’s it!
    在ViewPager源码中,我们可以很直观的看到它的调用过程:

    // ViewPager#onPageScrolled
    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);
        }
    }

    3). ViewPager.PageTransformer如何使用?

    首先,我们要弄懂transformPage方法的两个参数的含义。page当然指的就是滑动中的那个view,position这里定义为float,不是平时理解的int位置信息,而是当前滑动状态的一个表示,比如当滑动到正全屏时,position是0,而向左滑动,使得右边刚好有一部被进入屏幕时,position是1,如果前一夜和下一页基本各在屏幕占一半时,前一页的position是-0.5,后一页的posiotn是0.5,所以根据position的值我们就可以自行设置需要的alpha,x/y信息。
    Param 1: View page
    从上面的代码中,不难看出,page就是当前被滑动的页面,调试得知,每一个child view被NoSaveStateFrameLayout包装,也就是说page.getChildAt(0)即是每个page实际的child view。
    Param 2: float position
    position这个参数不看代码或者文档,总会误以为就是我们熟知的integer position,不过它实际上是滑动页面的一个相对比例,本质跟 1、2、3、4 这种position是一样的。
    比如知乎启动页共有6个页面,分别是A,B,C,D,E,F初始状态也就是A页面静止时,A页面的position正好是0,B页面是1。而后滑动页面(B -> A),在这个过程中A的position是间于[-1, 0],B页面则是间于[0, 1]。不过这个参数的文档却是简单不够直观,对照上面的例子,现在应该很清晰了。
    根据上面的分析,我们可以得出一个相对简单的自定义的transformer,对page(view)进行遍历,递增或者递减其parallaxCofficient,以得到我们预期的效果,具体的系数设置请参考代码。

    class ParallaxTransformer implements ViewPager.PageTransformer {
    
        float parallaxCoefficient;
        float distanceCoefficient;
    
        public ParallaxTransformer(float parallaxCoefficient, float distanceCoefficient) {
            this.parallaxCoefficient = parallaxCoefficient;
            this.distanceCoefficient = distanceCoefficient;
        }
    
        @Override
        public void transformPage(View page, float position) {
            float scrollXOffset = page.getWidth() * parallaxCoefficient;
    
            // ...
            // layer is the id collection of views in this page
            for (int id : layer) {
                View view = page.findViewById(id);
                if (view != null) {
                    view.setTranslationX(scrollXOffset * position);
                }
                scrollXOffset *= distanceCoefficient;
            }
        }
    }

    在ViewPager初始化的时候设置一下,便可以了。

    viewPager = (ViewPager) findViewById(R.id.pager);
    viewPager.setAdapter(pagerAdapter);
    viewPager.setPageTransformer(true, new ParallaxTransformer());

    4. 由视差滚动效果引起的思考

    通过上面的探索,其实我个人觉得ViewPager.PageTransformer上面大有可为,而不仅仅是可以做到视差滚动效果。比如我们做视差动画的时候是对整个页面View的child view设置一些视差系数以达到滚动速率差异的错位效果,然而我们其实可以仅仅对整个页面View设置一些过场动画,以达到生动的过渡效果。下面是一个页面放大的过渡效果实现,欢迎大家提出更多拓展方案。

    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) { // [-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);
            }
        }
    }


    以上仅是个人在开发中收集的经验,欢迎大家拍砖!

    展开全文
  • SeniorUI_高级UI汇总目录 一 PageTransformer * @param reverseDrawingOrder true if the supplied PageTransformer requires page views * to be drawn from last to first instead ...
  • 先来看看美丽说HIGO的全球买手圈滑动效果观察效果发现每次向左滑动时,右边的页4个View中,右下角的View速度最慢,视差最明显。 每次向右滑动时,左边的页4个View中,左上角的View速度最慢,视差最明显。 每次滑动...
  • Android的ViewPager类已经变成一个...标准的ViewPager实现工作得非常出色,但是在Google工作的牛人创建了名为PageTransformer的类。PageTransformer是一个接口,它允许你修改默认的页幻灯片动画。这样做你可以创建...
  • ViewPager动画的实现原理

    千次阅读 2015-02-28 17:02:24
    http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0115/2314.html 来源 ... 前言 前两天看到鲍永章分享的Great animations with PageTransformer以及农
  • 技术这东西就是需要日积月累的,每天学习一...今天复习一个小知识点,就是用ViewPager+Fragment+PageTransformer实现滑动动画,很简单,最后我会将源码demo下载地址附上,高手略过啊。 首先我们来看一下第一个效果:
  • Android ImageSlider实现广告轮播

    千次阅读 2016-11-27 22:25:02
    编辑推荐:稀土掘金,这是一个高质量的技术干货分享社区,web前端、Android、iOS、设计资源和产品,满足你的学习欲望。...前两天看到鲍永章分享的Great animations with PageTransformer以及农民伯伯分享的Create
  • 引导页_视差显示

    2015-12-01 17:34:13
    当用户下载完APP后,第一次启动时通常会有一个引导页,而这个引导页对于引导用户或介绍本产品有着很好的作用。一般三种方式实现: Viewpager ... 在ViewPager中,有一个接口叫做PageTransformer,其中有一
  • viewpager 滑动,缩放,子控件偏移引导页
  • http://ryanhoo.github.io/blog/2014/07/16/step-by-step-implement-parallax-animation-for-splash-screen-of-zhihu/ 前言 ...Parallax Scrolling (视差滚动),是一种常见的动画效果。视差一词来源于天文学,...
  • 前言 前两天看到鲍永章分享的Great ... animations with PageTransformer以及农民伯伯分享的Create ViewPager transitions 文章,都是通过ViewPager来实现酷炫的动画,而现在的App中ViewPage
  • ViewPager高级用法大全

    千次阅读 2016-07-29 12:49:16
    ViewPager高级用法大全
  • 本文主要讲解如何实现ViewPager自定义的页面切换动画效果。通过实现PageTransformer接口,然后利用position在这个过程的变化来动态设置页面的尺寸比例、透明度、以及偏移量。
  • Android ViewPager的使用总结

    万次阅读 2017-04-01 12:02:57
    ViewPager的基本使用ViewPager继承自ViewGroup,是一个View容器。用于装载多个View页面,可以在一个固定空间切换多个页面显示。 ViewPager使用也很简单,主要代码是实现PagerAdapter适配器。首先适配器继承...
  • 这篇博文是对viewpager...---------------- 割 割 割-----------------定制1:带有纵深的切换效果方法:通过自定义PageTransformer,实现transformPage(View page, float position)方法。PageTransformer depthTra...
  • ViewPager 滑动速度设置,并实现点击按钮滑动

    万次阅读 多人点赞 2015-11-06 15:49:33
    ViewPager 滑动速度设置,并实现点击按钮滑动    使用过ViewPager的童鞋,都会感觉到设置界面滑动挺简单的。... 第一个问题是,ViewPager在我们滑动放手后,速度和动画的变化率是固定的。  第二个问题的,我
1 2 3 4 5 ... 9
收藏数 172
精华内容 68
关键字:

pagetransformer 速度