package com.wasu.cs.widget.wheelview; import android.content.Context; import android.os.Handler; import android.os.Message; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.animation.Interpolator; import android.widget.Scroller; /** * Scroller class handles scrolling events and updates the */ public class WheelScroller { /** * Scrolling listener interface */ public interface ScrollingListener { /** * Scrolling callback called when scrolling is performed. * * @param distance the distance to scroll */ void onScroll(int distance); /** * Starting callback called when scrolling is started */ void onStarted(); /** * Finishing callback called after justifying */ void onFinished(); /** * Justifying callback called to justify a view when scrolling is ended */ void onJustify(); } /** Scrolling duration */ private static final int SCROLLING_DURATION = 400; /** Minimum delta for scrolling */ public static final int MIN_DELTA_FOR_SCROLLING = 1; // Listener private ScrollingListener mScrollinglistener; // Context private Context mContext; // Scrolling private GestureDetector mGestureDetector; private Scroller mScroller; private int mLastScrollY; private float lastTouchedY; private boolean isScrollingPerformed; /** * Constructor * * @param context the current context * @param listener the scrolling listener */ public WheelScroller(Context context, ScrollingListener listener) { mGestureDetector = new GestureDetector(context, mGestureListener); mGestureDetector.setIsLongpressEnabled(false); mScroller = new Scroller(context); mScrollinglistener = listener; mContext = context; } /** * Set the the specified scrolling interpolator * * @param interpolator the interpolator */ public void setInterpolator(Interpolator interpolator) { mScroller.forceFinished(true); mScroller = new Scroller(mContext, interpolator); } /** * Scroll the wheel * * @param distance the scrolling distance * @param time the scrolling duration */ public void scroll(int distance, int time) { mScroller.forceFinished(true); mLastScrollY = 0; mScroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION); setNextMessage(MESSAGE_SCROLL); startScrolling(); } /** * Stops scrolling */ public void stopScrolling() { mScroller.forceFinished(true); } /** * Handles Touch event * * @param event the motion event * @return */ public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastTouchedY = event.getY(); mScroller.forceFinished(true); clearMessages(); break; case MotionEvent.ACTION_MOVE: // perform scrolling int distanceY = (int) (event.getY() - lastTouchedY); if (distanceY != 0) { startScrolling(); mScrollinglistener.onScroll(distanceY); lastTouchedY = event.getY(); } break; } if (!mGestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) { justify(); } return true; } // gesture listener private SimpleOnGestureListener mGestureListener = new SimpleOnGestureListener() { public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // Do scrolling in onTouchEvent() since onScroll() are not call immediately // when user touch and move the wheel return true; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { mLastScrollY = 0; final int maxY = 0x7FFFFFFF; final int minY = -maxY; mScroller.fling(0, mLastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY); setNextMessage(MESSAGE_SCROLL); return true; } }; // Messages private final int MESSAGE_SCROLL = 0; private final int MESSAGE_JUSTIFY = 1; /** * Set next message to queue. Clears queue before. * * @param message the message to set */ private void setNextMessage(int message) { clearMessages(); animationHandler.sendEmptyMessage(message); } /** * Clears messages from queue */ private void clearMessages() { animationHandler.removeMessages(MESSAGE_SCROLL); animationHandler.removeMessages(MESSAGE_JUSTIFY); } // animation handler private Handler animationHandler = new Handler() { public void handleMessage(Message msg) { mScroller.computeScrollOffset(); int currY = mScroller.getCurrY(); int delta = mLastScrollY - currY; mLastScrollY = currY; if (delta != 0) { mScrollinglistener.onScroll(delta); } // scrolling is not finished when it comes to final Y // so, finish it manually if (Math.abs(currY - mScroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) { currY = mScroller.getFinalY(); mScroller.forceFinished(true); } if (!mScroller.isFinished()) { animationHandler.sendEmptyMessage(msg.what); } else if (msg.what == MESSAGE_SCROLL) { justify(); } else { finishScrolling(); } } }; /** * Justifies wheel */ private void justify() { mScrollinglistener.onJustify(); setNextMessage(MESSAGE_JUSTIFY); } /** * Starts scrolling */ private void startScrolling() { if (!isScrollingPerformed) { isScrollingPerformed = true; mScrollinglistener.onStarted(); } } /** * Finishes scrolling */ void finishScrolling() { if (isScrollingPerformed) { mScrollinglistener.onFinished(); isScrollingPerformed = false; } } }