Android Scroller简单用法

1.知识点

在了解Scorller类之前应先知道View的ScrollTo(int x, int y)/ScrollBy(int x, int y)之间的区别,了解什么是视图坐标,什么是布局坐标。之后我们来看一下Scroller的源码

Scoller一般用在自定义View中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class Scroller  { 
   
    private int mStartX;    //起始坐标点 ,  X轴方向 
    private int mStartY;    //起始坐标点 ,  Y轴方向 
    private int mCurrX;     //当前坐标点  X轴, 即调用startScroll函数后,经过一定时间所达到的值 
    private int mCurrY;     //当前坐标点  Y轴, 即调用startScroll函数后,经过一定时间所达到的值 
      
    private float mDeltaX;  //应该继续滑动的距离, X轴方向 
    private float mDeltaY;  //应该继续滑动的距离, Y轴方向 
    private boolean mFinished;  //是否已经完成本次滑动操作, 如果完成则为 true 
   
    //构造函数 
    public Scroller(Context context) { 
        this(context, null); 
    
    public final boolean isFinished() { 
        return mFinished; 
    
    //强制结束本次滑屏操作 
    public final void forceFinished(boolean finished) { 
        mFinished = finished; 
    
    public final int getCurrX() { 
        return mCurrX; 
    
     /* Call this when you want to know the new location.  If it returns true,
     * the animation is not yet finished.  loc will be altered to provide the
     * new location. */   
    //根据当前已经消逝的时间计算当前的坐标点,保存在mCurrX和mCurrY值中 
    public boolean computeScrollOffset() { 
        if (mFinished) {  //已经完成了本次动画控制,直接返回为false 
            return false
        
        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); 
        if (timePassed < mDuration) { 
            switch (mMode) { 
            case SCROLL_MODE: 
                float x = (float)timePassed * mDurationReciprocal; 
                ... 
                mCurrX = mStartX + Math.round(x * mDeltaX); 
                mCurrY = mStartY + Math.round(x * mDeltaY); 
                break
            ... 
        
        else
            mCurrX = mFinalX; 
            mCurrY = mFinalY; 
            mFinished = true
        
        return true
    
    //开始一个动画控制,由(startX , startY)在duration时间内前进(dx,dy)个单位,即到达坐标为(startX+dx , startY+dy)出 
    public void startScroll(int startX, int startY, int dx, int dy, int duration) { 
        mFinished = false
        mDuration = duration; 
        mStartTime = AnimationUtils.currentAnimationTimeMillis(); 
        mStartX = startX;       mStartY = startY; 
        mFinalX = startX + dx;  mFinalY = startY + dy; 
        mDeltaX = dx;            mDeltaY = dy; 
        ... 
    
}

一些方法介绍

1
2
3
4
5
6
7
8
9
10
11
12
mScroller.getCurrX() //获取mScroller当前水平滚动的位置 
mScroller.getCurrY() //获取mScroller当前竖直滚动的位置 
mScroller.getFinalX() //获取mScroller最终停止的水平位置 
mScroller.getFinalY() //获取mScroller最终停止的竖直位置 
mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置 
mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置 
   
//滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间 
mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms 
mScroller.startScroll(int startX, int startY, int dx, int dy, int duration) 
   
mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。

View的computeScroll()方法使用,此方法在绘制View的每一个子view时都被调用 

2.举例


实现下拉刷新的效果  
主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
public class CustomView extends RelativeLayout {
 
    private static final String TAG = "CustomView";
 
    private Scroller mScroller;
    private GestureDetector mGestureDetector;
    public boolean flag = true;
    public StateListener stateListener;
    public CustomView(Context context) {
        this(context, null);
    }
     
    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setClickable(true);
        setLongClickable(true);
        mScroller = new Scroller(context);
        mGestureDetector = new GestureDetector(context, new CustomGestureListener());
    }
    public interface StateListener
    {
        public void changeText();
        public void recoverText();
    }
    public void setStateListener(StateListener statelistener)
    {
        this.stateListener = statelistener;
    }
    //调用此方法滚动到目标位置
    public void smoothScrollTo(int fx, int fy) {
        int dx = fx - mScroller.getFinalX();
        int dy = fy - mScroller.getFinalY();
        smoothScrollBy(dx, dy);
    }
 
    //调用此方法设置滚动的相对偏移
    public void smoothScrollBy(int dx, int dy) {
 
        //设置mScroller的滚动偏移量
        mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
        invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果
    }
     
    //在绘制View时,会在draw()过程调用该方法。
    @Override
    public void computeScroll() {
     
        //先判断mScroller滚动是否完成
        if (mScroller.computeScrollOffset()) {
         
            //这里调用View的scrollTo()完成实际的滚动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
             
            //必须调用该方法,否则不一定能看到滚动效果
            postInvalidate();
        }
        super.computeScroll();
    }
     
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_UP :
            Log.i(TAG, "get Sy" + getScrollY());
            System.out.println(getScrollX()+"x--"+getScrollY()+"y");
            smoothScrollTo(0, 0);
            System.out.println("up");
            break;
        default:
            int distance = getScrollY();
            System.out.println("distance"+distance);
            if(distance <= 0)
            {
                flag = true;
                if(distance > -200)
                {
                    stateListener.recoverText();
                }
                else if(distance < -200)
                {
                    stateListener.changeText();
                }
                return mGestureDetector.onTouchEvent(event);
            }else
            {
                flag = false;
                return false;
            }
        }
        return super.onTouchEvent(event);
    }
     
    class CustomGestureListener implements GestureDetector.OnGestureListener {
 
        @Override
        public boolean onDown(MotionEvent e) {
            // TODO Auto-generated method stub
            return true;
        }
 
        @Override
        public void onShowPress(MotionEvent e) {
            // TODO Auto-generated method stub
             
        }
 
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            // TODO Auto-generated method stub
            return false;
        }
 
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            if(flag)
            {int dis = (int)((distanceY-0.5)/4);
            Log.i(TAG, dis + ".");
            smoothScrollBy(0, dis);}
            return false;
        }
 
        @Override
        public void onLongPress(MotionEvent e) {
            // TODO Auto-generated method stub
             
        }
 
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {
            // TODO Auto-generated method stub
            e1.getY();
            e2.getY();
            System.out.println(e1.getY()+"------"+e2.getY());
            return false;
        }
         
    }
}

结伴旅游,一个免费的交友网站:www.jieberu.com

推推族,免费得门票,游景区:www.tuituizu.com

原文地址:https://www.cnblogs.com/rabbit-bunny/p/4192837.html