public class ZoomListView extends ListView implementsSwipeListener {public static enumAction {
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop,
None
}private List actionListeners = new ArrayList();private boolean SwipeFlag = false;private static final int HORIZONTAL_MIN_DISTANCE = 30; //The minimum
private static final int VERTICAL_MIN_DISTANCE = 80; //The minimum distance
private float downX, downY, upX, upY; //Coordinates
private static final int INVALID_POINTER_ID = -1;private int mActivePointerId =INVALID_POINTER_ID;privateScaleGestureDetector mScaleDetector;private float mScaleFactor = 1.f;private float maxWidth = 0.0f;private float maxHeight = 0.0f;private floatmLastTouchX;private floatmLastTouchY;private floatmPosX;private floatmPosY;private floatwidth;private floatheight;publicZoomListView(Context context) {super(context);
mScaleDetector= new ScaleGestureDetector(getContext(), newScaleListener());
}publicZoomListView(Context context, AttributeSet attrs) {super(context, attrs);
mScaleDetector= new ScaleGestureDetector(getContext(), newScaleListener());
}public ZoomListView(Context context, AttributeSet attrs, intdefStyleAttr) {super(context, attrs, defStyleAttr);
mScaleDetector= new ScaleGestureDetector(getContext(), newScaleListener());
}
@Overrideprotected void onMeasure(int widthMeasureSpec, intheightMeasureSpec) {
width=MeasureSpec.getSize(widthMeasureSpec);
height=MeasureSpec.getSize(heightMeasureSpec);super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Overridepublic booleanonTouchEvent(@NonNull MotionEvent ev) {super.onTouchEvent(ev);final int action =ev.getAction();
mScaleDetector.onTouchEvent(ev);switch (action &MotionEvent.ACTION_MASK) {caseMotionEvent.ACTION_DOWN: {final float x =ev.getX();final float y =ev.getY();
mLastTouchX=x;
mLastTouchY=y;
mActivePointerId= ev.getPointerId(0);
downX=ev.getX();
downY=ev.getY();
SwipeFlag= true;break;
}caseMotionEvent.ACTION_MOVE: {final int pointerIndex =ev.findPointerIndex(mActivePointerId);final float x =ev.getX(pointerIndex);final float y =ev.getY(pointerIndex);final float dx = x -mLastTouchX;final float dy = y -mLastTouchY;float leftMargin = Math.abs(mPosX) /mScaleFactor;float rightMargin = this.getMeasuredWidth() - Math.abs(mPosX) /mScaleFactor;
rightMargin-= this.getResources().getDisplayMetrics().widthPixels /mScaleFactor ;
mPosX+=dx;
mPosY+=dy;if (mPosX > 0.0f)
mPosX= 0.0f;else if (mPosX
mPosX=maxWidth;if (mPosY > 0.0f)
mPosY= 0.0f;else if (mPosY
mPosY=maxHeight;
mLastTouchX=x;
mLastTouchY=y;
invalidate();
upX=ev.getX();
upY=ev.getY();float deltaX = downX -upX;float deltaY = downY -upY;//horizontal swipe detection
if (Math.abs(deltaX) >HORIZONTAL_MIN_DISTANCE) {//left or right
if (deltaX < 0 && SwipeFlag && leftMargin < 10) {
SwipeFlag= false;
OnAction(Action.LeftToRight);break;
}if (deltaX > 0 && SwipeFlag && rightMargin < 10) {
SwipeFlag= false;
OnAction(Action.RightToLeft);break;
}
}else{//vertical swipe detection
if (Math.abs(deltaY) >VERTICAL_MIN_DISTANCE) {//top or down
if (deltaY < 0 &&SwipeFlag) {
SwipeFlag= false;
OnAction(Action.TopToBottom);break;
}if (deltaY > 0 &&SwipeFlag) {
SwipeFlag= false;
OnAction(Action.BottomToTop);break;
}
}
}break;
}caseMotionEvent.ACTION_UP: {
mActivePointerId=INVALID_POINTER_ID;break;
}caseMotionEvent.ACTION_CANCEL: {
mActivePointerId=INVALID_POINTER_ID;break;
}caseMotionEvent.ACTION_POINTER_UP: {final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >>MotionEvent.ACTION_POINTER_INDEX_SHIFT;final int pointerId =ev.getPointerId(pointerIndex);if (pointerId ==mActivePointerId) {final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX=ev.getX(newPointerIndex);
mLastTouchY=ev.getY(newPointerIndex);
mActivePointerId=ev.getPointerId(newPointerIndex);
}break;
}
}return true;
}
@Overridepublic voidonDraw(Canvas canvas) {super.onDraw(canvas);
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.restore();
}
@Overrideprotected voiddispatchDraw(@NonNull Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);if (mScaleFactor == 1.0f) {
mPosX= 0.0f;
mPosY= 0.0f;
}
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);super.dispatchDraw(canvas);
canvas.restore();
invalidate();
}private class ScaleListener extendsScaleGestureDetector.SimpleOnScaleGestureListener {
@Overridepublic booleanonScale(ScaleGestureDetector detector) {
mScaleFactor*=detector.getScaleFactor();
mScaleFactor= Math.max(1.0f, Math.min(mScaleFactor, 3.0f));
maxWidth= width - (width *mScaleFactor);
maxHeight= height - (height *mScaleFactor);
invalidate();return true;
}
}
@Overridepublic voidOnAction(Action action) {for(SwipeListener listener : actionListeners){
listener.OnAction(action);
}
}public voidaddActionListener(SwipeListener listener)
{
actionListeners.add(listener);
}
}