ViewPager源码学习——滑动篇

本篇主要分析ViewPager动起来是怎么处理的

//从方法名称看能知道,已知position的位置,滑动到相应的位置,第二个方法为 
//是否是平滑滑动,第三个成为是滑动的速率吧,第四个参数是否回调
//onPageSelected方法
private void scrollToItem(int item, boolean smoothScroll, int velocity,
            boolean dispatchSelected) {
        //根据传入的Position,从mItems中获取ItemInfo
        final ItemInfo curInfo = infoForPosition(item);
        int destX = 0;
        if (curInfo != null) {
            //得到宽
            final int width = getClientWidth();
            //得到X需要移动的位置
            destX = (int) (width * Math.max(mFirstOffset,
                    Math.min(curInfo.offset, mLastOffset)));
        }
        //需要平滑滑动
        if (smoothScroll) {
            //开始平滑滚动
            smoothScrollTo(destX, 0, velocity);
            if (dispatchSelected) {
                //对onPageSelected方法进行回调
                dispatchOnPageSelected(item);
            }
        } else {
            if (dispatchSelected) {
                //回调onPageSelected方法
                dispatchOnPageSelected(item);
            }
            //滚动完成的一些处理
            completeScroll(false);
            //如果没调用平滑滚动,就将ViewPager直接滚动到传入的界面
            scrollTo(destX, 0);
            //回调pageScrolled方法
            pageScrolled(destX);
        }
    }

实现平滑滚动,该方法主要是求出来当前x的位置,需要移动的x位置,当前y的位置,需要移动到y的位置
通过startScroll和重写computeScroll方法,实现的缓慢滚动的效果

void smoothScrollTo(int x, int y, int velocity) {
        // ViewPager如果没有View,清除缓存
        if (getChildCount() == 0) {
            // Nothing to do.
            setScrollingCacheEnabled(false);
            return;
        }
        int sx;
        //判断上一次滑动的动画是否结束
        boolean wasScrolling = (mScroller != null) && !mScroller.isFinished();
        //从代码来看,如果为正在运动的scroller,当前位置为getCurrX
        //否则为getScrollX
        if (wasScrolling) {
            //判断当前是滚动了,如果为真。sx为计算的当前位置,否则为初始坐标
            sx = mIsScrollStarted ? mScroller.getCurrX() : mScroller.getStartX();
            // And abort the current scrolling.
            //将滚动动画停止
            mScroller.abortAnimation();
            setScrollingCacheEnabled(false);
        } else {
            sx = getScrollX();
        }
        //假如我现在在第一个界面,只显示了一半
        //我调用smoothScrollTo(int x, int y, int velocity) 传入1080(如果getScrollX为1080即为第二个页面),0,0
        //算出y滑动的距离
        int sy = getScrollY();
        //算出需要滑动的X距离
        int dx = x - sx;
        //算出需要滑动的Y距离
        int dy = y - sy;
        //如果dx和dy都等于0,证明,滑动已经结束
        if (dx == 0 && dy == 0) {
            completeScroll(false);
            populate();
            //设置状态为SCROLL_STATE_IDLE
            setScrollState(SCROLL_STATE_IDLE);
            return;
        }
        //开启缓存
        setScrollingCacheEnabled(true);
        //设置状态为SCROLL_STATE_SETTLING
        setScrollState(SCROLL_STATE_SETTLING);
        //下面的代码就是通过已经滚动的比例计算,计算剩下需要滚动内容所需要的时间
        final int width = getClientWidth();
        final int halfWidth = width / 2;
        final float distanceRatio = Math.min(1f, 1.0f * Math.abs(dx) / width);
        final float distance = halfWidth + halfWidth
                * distanceInfluenceForSnapDuration(distanceRatio);

        int duration;
        velocity = Math.abs(velocity);
        if (velocity > 0) {
            duration = 4 * Math.round(1000 * Math.abs(distance / velocity));
        } else {
            final float pageWidth = width * mAdapter.getPageWidth(mCurItem);
            final float pageDelta = (float) Math.abs(dx) / (pageWidth + mPageMargin);
            duration = (int) ((pageDelta + 1) * 100);
        }
        duration = Math.min(duration, MAX_SETTLE_DURATION);

        // Reset the "scroll started" flag. It will be flipped to true in all places
        // where we call computeScrollOffset().
        //这个方法设置为flase,但是却在每一个调用
        //computeScrollOffset方法之前只为true
        mIsScrollStarted = false;
        //开启平滑滚动
        mScroller.startScroll(sx, sy, dx, dy, duration);
        //不断进行绘制,会回调computeScroll方法
        ViewCompat.postInvalidateOnAnimation(this);
    }       

当调用postInvalidateOnAnimation会不断的绘制视图,从而实现平滑滚动

@Override
    public void computeScroll() {
        //当前正在滚动
        mIsScrollStarted = true;
        //如果当前动画没有执行完
        if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
            //得到滑动的位置,可以理解成旧的位置
            int oldX = getScrollX();
            int
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值