package com.qmusic.controls;
import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.RelativeLayout;
import android.widget.Scroller;
public class BSwipeView2 extends RelativeLayout {
static final String TAG = BSwipeView2.class.getSimpleName();
public final static int SWIPE_MODE_NONE = 0;
public final static int SWIPE_MODE_BOTH = 1;
public final static int SWIPE_MODE_RIGHT = 2;
public final static int SWIPE_MODE_LEFT = 3;
private final static int TOUCH_STATE_REST = 0;
private final static int TOUCH_STATE_SCROLLING_X = 1;
int swipeMode = SWIPE_MODE_BOTH;
int touchSlop;
float lastMotionX, lastMotionY;
boolean swipe;// need to swipe for this swipe
boolean swiping;// swipe state;
boolean toRight;
int halfWidth;
OnSwipeCallback callback;
Scroller scroller;
int touchState = TOUCH_STATE_REST;
View frontView, backView;
int finalDiffX;
public BSwipeView2(Context context) {
super(context);
init(null);
}
public BSwipeView2(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public BSwipeView2(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs);
}
private void init(AttributeSet attrs) {
scroller = new Scroller(getContext(), new DecelerateInterpolator());
}
public interface OnSwipeCallback {
void onSwipe(BSwipeView2 view, boolean toRight);
void onMove(BSwipeView2 view, boolean toRight, float percent);
void onClick(BSwipeView2 view);
}
public void setCallback(OnSwipeCallback callback) {
this.callback = callback;
}
public void setSwipeMode(int mode) {
swipeMode = mode;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = MotionEventCompat.getActionMasked(ev);
final float x = ev.getX();
final float y = ev.getY();
if (isEnabled() && swipeMode != SWIPE_MODE_NONE) {
switch (action) {
case MotionEvent.ACTION_MOVE:
// Log.d(TAG, "onInterceptTouchEvent:move");
swiping = checkInMoving(x, y);
if (swiping) {
touchState = TOUCH_STATE_SCROLLING_X;
return true;
} else {
return false;
}
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "onInterceptTouchEvent:down");
if (backView == null || frontView == null) {
backView = this.getChildAt(0);
frontView = this.getChildAt(1);
}
touchState = TOUCH_STATE_REST;
lastMotionX = x;
lastMotionY = y;
return false;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "onInterceptTouchEvent:cancel");
touchState = TOUCH_STATE_REST;
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "onInterceptTouchEvent:up");
return touchState == TOUCH_STATE_SCROLLING_X;
default:
// Log.d(TAG, "onInterceptTouchEvent:default");
break;
}
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = MotionEventCompat.getActionMasked(ev);
float currentMotionX = ev.getX();
float currentMotionY = ev.getY();
switch (action) {
case MotionEvent.ACTION_MOVE: {
// Log.d(TAG, "onTouchEvent:move");
float diffX = currentMotionX - lastMotionX;
toRight = diffX > 0;
if ((toRight && (swipeMode == SWIPE_MODE_RIGHT || swipeMode == SWIPE_MODE_BOTH))
|| (!toRight && (swipeMode == SWIPE_MODE_LEFT || swipeMode == SWIPE_MODE_BOTH))) {
swipe = Math.abs(diffX) > halfWidth;
float percent = Math.abs(diffX) / halfWidth;
if (callback != null) {
callback.onMove(this, toRight, percent);
}
swiping = true;
scrollOpen(diffX * 0.5f);
}
break;
}
case MotionEvent.ACTION_DOWN: {
Log.d(TAG, "onTouchEvent:down");
touchState = TOUCH_STATE_REST;
lastMotionX = currentMotionX;
lastMotionY = currentMotionY;
break;
}
case MotionEvent.ACTION_UP: {
Log.d(TAG, "onTouchEvent:up");
if (swiping) {
swiping = false;
scrollBack();
} else if (callback != null) {
if (!checkInMoving(currentMotionX, currentMotionY)) {
Log.d(TAG, "clicked");
callback.onClick(this);
} else {
Log.d(TAG, "has moved. abort click");
}
}
break;
}
case MotionEvent.ACTION_CANCEL: {
Log.d(TAG, "onTouchEvent:cancel");
if (swiping) {
swiping = false;
scrollBack();
}
break;
}
default: {
// Log.d(TAG, "onTouchEvent:default");
break;
}
}
invalidate();
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
halfWidth = getMeasuredWidth() / 2;
// int height = getMeasuredHeight();
// Log.e(TAG, "onMeasure:w/2:" + halfWidth + ";h:" + height);
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
// Log.i(TAG, "computeScroll:111");
scrollTo(scroller.getCurrX(), 0);
invalidate();
} else {
// Log.i(TAG, "computeScroll:222");
if (!swiping && swipe) {
swipe = false;
onClose();
}
}
}
private boolean checkInMoving(float x, float y) {
final int xDiff = (int) Math.abs(x - lastMotionX);
final int yDiff = (int) Math.abs(y - lastMotionY);
final int touchSlop = this.touchSlop;
boolean xMoved = xDiff > touchSlop;
if (xDiff > yDiff && xMoved) {
return true;
}
return false;
}
private void scrollOpen(float diffX) {
finalDiffX = (int) diffX;
this.scrollTo(-finalDiffX, 0);
invalidate();
}
private void scrollBack() {
scroller.startScroll(-finalDiffX, 0, finalDiffX, 0, 300);
invalidate();
}
private void onClose() {
if (callback != null) {
callback.onSwipe(BSwipeView2.this, toRight);
}
}
}