ViewPager学习(1) - transformer 页面切换

做为我viewpager的第一篇,我觉得说一说这个页面变换还是很对头的,这个页面变换可是我们精通viewpager必会的第一项

何为页面切换效果,就是我们滑动viewpager时当前页和下一页以什么样式呈现,废话不多说,先来看下效果图:


ezgif.com-video-to-gif.gif

实现原理:

大家看着像是用动画实现的,其实很简单,google已经给我们做好准备了,实现 ViewPager.PageTransformer 这个接口,然后把这个实现对象设置到viewpager里即可。


// 这是实现页面切换接口的实现类类
public class AlpheScaleTransformer implements ViewPager.PageTransformer {

      @Override
    public void transformPage(View page, float position) {
      ....
    }

}

// 然后把这个实现对象设置到viewpager里
 mViewPager.setPageTransformer(true, new AlpheScaleTransformer());

看着是不是很简单啊,其实细细想来,这和实现动画是一个原理。何为动画,快速切换的静态图片罢了,在我们切换viewpager页面时,页面随着手指滚动,滚动一次,viewpager就会调一次 ViewPager.PageTransformer 这个接口实现类来重置当前页和下一页的样式,在这里我们做缩放,透明度等各种变换来操作view的各种属性,然后随着系统16ms刷新一帧,也就成了我们看到的样子。google已经提供了这个接口,而且还放出了官方的demo,所以大家不要怕,这个切换的知识点很简单的,所以我再viewpager的第一篇才来说这块。

google官方demo:

package com.example.zb.bloodcrownviewpagertransformer.transformer;

import android.support.v4.view.ViewPager;
import android.view.View;

public class GooglePageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View page, float position) {
        int pageWidth = page.getWidth();

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            page.setAlpha(0);

        } 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 { // (1,+Infinity]
            // This page is way off-screen to the right.
            page.setAlpha(0);
        }
    }
}

我的实现:

 public class AlpheScaleTransformer implements ViewPager.PageTransformer {

    private float minAlphe = 0.3f;
    private float minScale = 0.7f;

    @Override
    public void transformPage(View page, float position) {

        if (position < -1 || position > 1) {
            page.setAlpha(1);
            page.setTranslationX(0);
            page.setScaleX(1);
            page.setScaleY(1);
            return;
        }

        if (position >= -1 && position <= 0) {
            return;
        }

        if (position > 0 && position <= 1) {
            page.setAlpha(minAlphe + (1 - minAlphe) * (1 - Math.abs(position)));
            page.setScaleX(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setScaleY(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setPivotX(page.getWidth() / 2);
            page.setPivotY(page.getHeight() / 2);
            page.setTranslationX(page.getWidth() * -position);
        }
    }
}

实现要点

目标接口:

public class AlpheScaleTransformer implements ViewPager.PageTransformer {

      @Override
    public void transformPage(View page, float position) {
      ....
    }

}

上面的热闹看完了,那么我们来具体的说下实现的要点:

  • 接口参数介绍
  • 接口被谁调用,调用次数
  • 结合实际理解接口参数

接口参数介绍

ViewPager.PageTransformer 接口里面只有一个方法,用来不停刷新页面样式的。那么我们观看里面的 transformPage 这个方法,参数是一个view和一个数值。view自然是viewpager的每个页面了,position则是当前这个view页面所处的位置。

接口被谁调用,调用次数

那么大伙想一想我们滑动viewpager时是几个页面在动?咱就说一般的viewpager,那么发生变化的页面一个是当前页,一个是下一页或是上一页啦,那么算下来就是2个页面,就是2个view啦。这么说的话2个页面都是同时再运动,那么 transformPage(View page, float position) 这个方法必然也是会被调用多次了。会调用几次,被谁调用?也许大家会猜测是参与运动变化的这2个页面。经过测试发现不仅仅是这2个页面会调用这个接口方法,而是viewpager适配器中所有缓存的view都会调用这个接口方法,大家想过没有,为什么会是这样,因为viewpager不知道缓存的view是不是正在显示,所以干脆缓存的所有view都去做页面变换,万一都在显示呢,举个例子,大家都看过同时显示3个view的viewpager吧

结合实际理解接口参数

transformPage(View page, float position) 里面就2个参数,view大家都明白了吧,每个缓存的view都会跑一次这个方法。position比较麻烦也是这个方法的核心,所以要重点细说。上面说position是描述页面所处的位置,在开始变换前,中间的页面(也是当前页面)position是0,左边的页面position是-1,右边的页面position是1。记住中间页面position永远是0,整数表示当前页右边的页,负数表示当前页左边的页

举个例子,当前页是第二页,我们左滑,实际是第二页往左运动到手机尽头不显示,第三页从右边慢慢进入到手机屏幕代替第二页的位置。postion的变化:

  • 第二页(原当前页) 0 ~ -1
  • 第三页1 ~ 0

第二页从当前页运动到屏幕左侧,所以是 从0 ~ -1 的变化。
第三页因为是在第二页的右边,所以是 从1 ~ 0的变化。

大家想想是不是这样,整数表示右边,第三页的确是在第二页的右边,所以第三页开始position是1 ,中间的当前页因为是position0,所以第三页运动到屏幕中间代码第二页时,position就是0啦。第二页呢因为是中间页,开始position是0,第二页向左运动,因为第二页在第三页的左边,所以运动结束时是-1。

大家来看张position变换的表:(这张图是我扒来的)


猎豹截图20170901013453.png

看上面这张图,基本说明了position的数值范围,position都是以1做为整数变更的,0是中间页面,-1是左边的页面,那么-2就是左边的左边,正数同理。一般viewpager的页面切换至涉及到2个页面,取值 < -1的,> 1的一般都是不可见的页面,负数都是表示左边的页面或是往左边一栋的页面,正数表示右边的页面或是往右边一栋的页面,这就是viewpager页面切换的核心,参透position参数的变化,说道这里大伙看看上面google的官方实现或是我的现实都可以,我的实现里position < -1 的我都没有操作,所以在效果图里,左边的页面除了默认的位移什么效果都没有,变化都是来自于右边就是因为position的取舍。默认都是会带上位移的,我们给view一个反向的位移就可以让view实现在原地变换的效果了。

 if (position > 0 && position <= 1) {
            page.setAlpha(minAlphe + (1 - minAlphe) * (1 - Math.abs(position)));
            page.setScaleX(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setScaleY(minScale + (1 - minScale) * (1 - Math.abs(position)));
            page.setPivotX(page.getWidth() / 2);
            page.setPivotY(page.getHeight() / 2);
            page.setTranslationX(page.getWidth() * -position);  // 这行就是加一个反响的位移
        }

总结

上面我就是说了下position的数值变化,其他的没怎么说,各位看官要是理解的不是很透的话请看参考资料,尤其是参考资料里 transformer 变换的库(ViewPagerTransforms),transformer变化的核心都在这些transformer的实现类上面了。

另外我们在自己计算view属性变换的公式时,只要计算好一个方向的公式就好了,反方向postion的数值会走反向变化。

项目地址


参考资料


第三方变换库

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容