View的滑动(1)——Scroller

View的滑动有七种方法,我想重点记录一下其中的两种,其实也可以说是一种,Scroll相关。


先列举其他几种吧:

1、layout()方法,直接调用layout方法使得子view重新布局。
2、offsetLeftAndRight()和offsetTopAndBottom(),类似layout()方法。
3、layoutParams。
4、Animator属性动画
5、ViewDragHelper,这个下一篇详细记录。


下面开始进入Scroller了:

一、ScrollTo()和ScrollBy()

在使用scroller之前先了解一下这两个方法。

它们是用来对view里面的内容进行滚动的,滚动的方向和给的值正负相反。

有的资料说这是因为,移动的其实是手机屏幕。

所以用户看到的内容就会相对反向运动了。我感觉不是很正确,不过这么理解倒是对使用没有什么影响,这里有一篇资料我觉得蛮有道理的,不过我只是半懂。http://www.tuicool.com/articles/z6rmim

好了,看一下我的自定义view的源码吧:

@Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lastX = (int) event.getRawX();
            lastY = (int) event.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            curX = (int) event.getRawX();
            curY = (int) event.getRawY();
            int offsetX = curX - lastX;
            int offsetY = curY - lastY;
            ((View) getParent()).scrollBy(0 - offsetX, 0 - offsetY);
            lastX = curX;
            lastY = curY;
            break;
        case MotionEvent.ACTION_UP:
            View viewGroup=(View)getParent();
            scroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY());
            break;
        default:
            break;
        }
        return true;
    }

最后的action_up那里不用管,重点是action_move。
由于之前说过了,移动的是view内部的内容所以在使用scrollBy的时候就先得到当前view的父view。然后通过计算手指移动距离进行scroll就好了。


二、Scroller

好了,在实现完action_move后,其实视图就可以随着手指滑动了。

但是如果是通过按钮,一个button来实现滑动,那么上面说的两个方法就会很突兀。
这里写图片描述
这就是为什么要使用scroller的原因。

跟scroller相关的方法有三个:
startScroll()
computeScroll()
computeScrollOffset()

哦,还有个构造方法,,
假设构造好了,Scroller scroller=new Scroller(context);

接下来就是在适当的时候调用startScroll()方法了。

这里我们在action_up那里调用,实现的效果就是让跟随手指滑动的view在手指松开后自动回去。

代码如下:

case MotionEvent.ACTION_UP:
            View viewGroup=(View)getParent();
            scroller.startScroll(viewGroup.getScrollX(), viewGroup.getScrollY(), -viewGroup.getScrollX(), -viewGroup.getScrollY());
            invalidate();
            break;

这里又涉及到了另一个方法,getScrollX(),这个可以理解成是用来得到试图左上角和屏幕左上角的距离的方法。

比如本来视图和屏幕是重合的,结果调用scrollTo(-10,-10)使得试图左移了10px,那么这个时候就不重合了,于是getScrollX()就会返回10。显然,这个方法其实记录了滑动的时候起点和终点的直线距离,有点类似物理里面的位移。

解决了这个方法后,再来看startScroll的四个参数

  public void startScroll(int startX, int startY, int dx, int dy)

从名字很好猜测,分别是起始x,y和需要滑动的距离x,y。

接下来看这个函数的代码发现,只是对一些变量进行了操作,并没有开启什么动画或者滑动。

 public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        mMode = SCROLL_MODE;
        mFinished = false;
        mDuration = duration;
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;
        mDurationReciprocal = 1.0f / (float) mDuration;
    }

可以看到,就是设置了一下startX,finalX和滑动时间这种的,所以并没有真的像名字描述的那样开始滑动。

那么是什么时候开始的呢,是在使用了这个函数的下面一排,invalidate()。

invalidate()会调用draw(),draw会调用computeScroll()。


这个computeScroll()是需要我们重写的,代码如下:

@Override
    public void computeScroll() {
        // TODO Auto-generated method stub
        super.computeScroll();
        if (scroller.computeScrollOffset()) {
            ((View) getParent()).scrollTo(scroller.getCurrX(),
                    scroller.getCurrY());
        }
        invalidate();
    }

可以发现,到这里,提到的三个函数全部都出现了,这里先说computeScrollOffset()方法吧。

它会返回一个boolean,如果滑动结束了,就返回false,反之返回true。它是通过什么判断的呢,是通过之前在startScroll里面设置的时间来进行判断的。

我截取源代码中的几句展示出来,多了看的头晕。

if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                float x = timePassed * mDurationReciprocal;

                if (mInterpolator == null)
                    x = viscousFluid(x); 
                else
                    x = mInterpolator.getInterpolation(x);

                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;

只需要注意到,判断条件是时间,操作中更改了mCurrx这些属性就好了。

理解了这个方法之后,对于刚才的computeScroll()就清晰 很多,下面是computeScroll在判断完毕之后我们自己实现的代码:

if (scroller.computeScrollOffset()) {
            ((View) getParent()).scrollTo(scroller.getCurrX(),
                    scroller.getCurrY());
        }
        invalidate();

很简单,滑到计算的那个地方去。


下面,总结一下绘制的流程。

view捕捉到action_up,调用startScroll()来初始化滑动参数。
然后通过invalidate()调用draw()。
draw会调用computeScroll()。
computeScroll()首先通过cmoputeScrollOffset()判断是否结束,同时改变滑动位置的值,接着调用scrollTo进行滑动。
最后再次通过invalidate()来调用draw,完成循环的过程。

参考:http://blog.csdn.net/xiaanming/article/details/17483273

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值