叨叨ViewPager那些事儿(二)

前言

上一篇叨叨ViewPager那些事儿(一)说了一点ViewPager概况,这篇打算说说实际应用。


从动画效果说起

先祭上一份谷歌官方的Transformer示例
效果如下


代码实现是这样

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

乍一看有点懵懂,一步一问 慢慢来

transformPage(View view, float position)两个参数是何含义


第一个参数为各页卡对象,第二个是各个页卡对于当前所展示页卡的相对位置,例如,当前页卡的position为0,下一张位置为1,前一张则为-1。而ViewPager滑动中,position的值是处于平滑变化中的,这就为我们处理动画提供了机会。

为何position < -1position > 1时设置可见度为0
如前问分析,position < -1position > 1指代页卡所处区间为[-Infinity,-1)和(1,+Infinity],在可见范围之外,从节省绘制资源的角度出发,自然可见度为0。

position (0,1]区间时为何要设置偏移度为(pageWidth * -position)
官方注释Counteract the default slide transition,抵消页面滑动时的默认偏移量。如页面处在中间时偏移量为0*width,移至右边为1*width,从中间往右移除时position0-->1渐变,默认偏移量为position*width

滑动动画的缩放效果如何计算
如效果图示,当下一张页卡相对位置从1-->0变化时,scale的变化方向为MIN_SCALE(m)-->1,不妨列个公式
(1-position)/(position-0)=(m-scale)/(scale-1)s=(1-position)/(1-position*m)(对。。跟示例代码不一样。。但是效果一样哦。。
也可以理解为1-scale=|(m-1)|/(1-0)*position,scale从1-->m,位置从0-->1,即每单位position的变化量为|(m-1)|/(1-0),乘上position得出变化量。

理论储备到位之后,自力更生的第一步就是,实践!
下边我们来写一个左右位移,同时展示三张卡片的动画,预想中效果大概是这样


根据设想计算,左右两边的页卡大小应为中间大页卡的0.9倍,左右页卡的偏移量约为±0.2倍页卡宽。
故设定MIN_Trans_INDEX = 0.2f,MIN_SCALE_INDEX = 0.9f。如上分析,我们只关心[-1,1]区间页卡的动画,
每单位position的scale变化量绝对值为(1-MIN_SCALE_INDEX)/(1-0),即1-scale=|position|*(1-MIN_SCALE_INDEX)/(1-0)scale=1-|position|*(1-MIN_SCALE_INDEX)
同理,每单位position的translationx变化量为pageWidth*(1-MIN_Trans_INDEX)/(1-0),即|0-translationx|=|position|*pageWidth*(1-MIN_Trans_INDEX)|translationx|=|position|*pageWidth*(1-MIN_Trans_INDEX),然而viewpager页卡滑动过程中的默认偏移量绝对值为pageWidth * position,故需在上式基础上减pageWidth * position,|translationx|=|position|*pageWidth*MIN_Trans_INDEX
计算完毕,写入代码后发现,效果是出来了,但是反应好像永远。慢半拍。当前页滑动到位后,下一页才出现,体验不太美妙,如下动图所示

查看代码后思考,应该是[-1,1]位置限定导致,左右两页分别滑动到-1和1时才开始做动画,而此时这两张页卡已经出现在屏幕上,所以看起来就像“慢了半拍”。
尝试增加一点“缓冲量”,改动如下

public class MyTransPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_Trans_INDEX = 0.2f;
    private static final float MIN_SCALE_INDEX = 0.9f;

    @Override
    public void transformPage(@NonNull View page, float position) {
        int pageWidth = page.getWidth();
        if (position < -1.1) { // [-Infinity,-1.1)
            // This page is way off-screen to the left.
            page.setAlpha(0);
        } else if (position <= 0) { // [-1.1,0]
            // Use the default slide transition when moving to the left page
            page.setAlpha(1);
            page.setTranslationX(-pageWidth * position * MIN_Trans_INDEX);
            page.setScaleX((1 - MIN_SCALE_INDEX) * position + 1);
            page.setScaleY((1 - MIN_SCALE_INDEX) * position + 1);
            Log.i("test", page.getTag()+"--"+((1 - MIN_SCALE_INDEX) * position + 1));
        } else if (position <= 1.1) { // (0,1.1]
            // Fade the page out.
            page.setAlpha(1);
            // Counteract the default slide transition
            page.setTranslationX(-pageWidth * position * MIN_Trans_INDEX);
            page.setScaleX(1 - (1 - MIN_SCALE_INDEX) * position);
            page.setScaleY(1 - (1 - MIN_SCALE_INDEX) * position);
        } else { // (1.1,+Infinity]
            // This page is way off-screen to the right.
            page.setAlpha(0);
        }
    }
}

再次运行。这才是想要的效果嘛


问题来了

之前遇到过一个现象,刷新ViewPager,调用notifyDataSetChanged(),如下。

诶,怎么肥事!左右两边的页卡去哪了!冷静一下,刷新时对当前页卡重绘,若不需滚动,则pageoffset始终为0,transformer的动画效果无法显示。看来要想平稳刷新,还需手动更新单条数据。
行动起来,更改如下逻辑

@Override
    public void onClick(View v) {
        if (v.getId() == R.id.tv_notify) {
            if (mCurPageIndex == 3) {//测试,代表逻辑需跳转到的页卡
                isNeedNotify = true;
            }
            //更新当前页卡数据
            updateViewPager(mCurPageIndex);
        }
    }
private void updateViewPager(int position) {
        if (isNeedNotify) {//需要滚动时,调用notifyDataSetChanged重走instantiateItem和destroyItem逻辑
            mPagerAdapter.notifyDataSetChanged();
            mViewPager.setCurrentItem(3);
            isNeedNotify = false;
        }
        //仅需更新当前页时则单独刷新当前页卡view
        MyViewPagerItem item = mPageItemList.get(position);
        if (item != null) {
            PageItemBean bean = new PageItemBean();
            bean.num = position;
            bean.tip = mContext.getString(R.string.num_tip, position + 1 + "");
            item.updateUI(bean);
        }
    }

重跑程序,问题解决,Demo先放下。
为解决问题临时想的方案,是实现更新的一条思路但感觉不够优,欢迎各路大神指点。


最后

本想多写一点,但动画已经占了不少篇幅,先在这结束吧。这个系列会努力补充,欢迎多多指点和关注。

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

推荐阅读更多精彩内容