Skip to content

Instantly share code, notes, and snippets.

@MartinRGB
Created October 13, 2017 07:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MartinRGB/3f0f02bc4d272e47a241fe4cd3a5dc76 to your computer and use it in GitHub Desktop.
Save MartinRGB/3f0f02bc4d272e47a241fe4cd3a5dc76 to your computer and use it in GitHub Desktop.
MultiGestureDetector
package com.martinrgb.multitask.util;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.Toast;
/**
* Created by MartinRGB on 2017/9/11.
*/
public class MultiGestureDetector implements GestureDetector.OnGestureListener,GestureDetector.OnDoubleTapListener,View.OnTouchListener{
private VelocityTracker mVelocityTracker;
private static final int SWIPE_DISTANCE_THRESHOLD = 200;
private static final int SWIPE_VELOCITY_THRESHOLD = 2000;
private static final int LOG_TYPE_I = 0;
private static final int LOG_TYPE_E = 1;
private static final String TAG = "MultiGestureDetector";
private GestureDetector mGestureDetector;
private boolean firstJudge = false;
//创建监听器借口
public interface SimpleGestureListener
{
void onDown(MotionEvent event);
void onLongPress(MotionEvent event);
void onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY,float velocityX,float velocityY);
void onSwipeLeft(float velocity);
void onSwipeRight(float velocity);
void onSwipeBottom(float velocity);
void onSwipeTop(float velocity);
void onUp(MotionEvent event);
void onDoubleTap(MotionEvent event);
void onSwipeTopFix();
void onVelocityStop(boolean boo);
void onTriggerJudge(boolean boo);
}
//实例化一个监听器的数值为空
private SimpleGestureListener mSimpleGestureListener = null;
public MultiGestureDetector(SimpleGestureListener simpleGestureListener) {
mGestureDetector = new GestureDetector(this);
mSimpleGestureListener = simpleGestureListener;
}
public boolean onDown(MotionEvent event) {
//printTag(TAG,true,LOG_TYPE_I,event);
//mSimpleGestureListener.onDown(event);
return true;
}
public void onShowPress(MotionEvent event) {
printTag(TAG,true,LOG_TYPE_I,event);
//Reset
mSimpleGestureListener.onTriggerJudge(false);
xChangingV = 0;
yChangingV = 0;
latestTrackedVelocityX = 0;
latestTrackedVelocityY = 0;
scrollInProgress = false;
firstJudge = false;
}
public void onLongPress(MotionEvent event) {
//printTag(TAG,true,LOG_TYPE_I,event);
mSimpleGestureListener.onLongPress(event);
}
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//printTag(TAG,true,LOG_TYPE_E,null);
//Log.e("SFACT","onScroll" + " Distance X is " + Float.toString(e2.getX() - e1.getX()) + " Distance Y is " + Float.toString(e2.getY() - e1.getY()));
mSimpleGestureListener.onScroll(e1,e2,e2.getX()-e1.getX(),e2.getY()-e1.getY(),xVelocity,yVelocity);
return true;
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
//onSwipeRight();
mSimpleGestureListener.onSwipeRight(velocityX);
// Log.e("SFACT","Swipe Right,Velocity is" + velocityX);
} else {
//onSwipeLeft();
mSimpleGestureListener.onSwipeLeft(velocityX);
// Log.e("SFACT","Swipe Left,Velocity is" + velocityX);
}
result = true;
}
}
else if (Math.abs(diffX) < Math.abs(diffY)){
if (Math.abs(diffY) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
// onSwipeBottom();
mSimpleGestureListener.onSwipeBottom(velocityY);
// Log.e("SFACT","Swipe Bottom,Velocity is" + velocityY);
} else {
//onSwipeTop();
//Log.e("SFACT","Swipe Top,Velocity is" + velocityY);
mSimpleGestureListener.onSwipeTop(velocityY);
}
result = true;
}
else{
Log.e("SFACT","Should Fix Error");
mSimpleGestureListener.onSwipeTopFix();
}
}
else{
// Log.e("SFACT","4567" + "ERROR");
}
} catch (Exception exception) {
exception.printStackTrace();
}
printTag(TAG,true,LOG_TYPE_E,null);
return result;
}
private boolean hasRecycled = false;
private float xVelocity,yVelocity;
private float xChangingV,yChangingV;
private timeCheckHandler mTimeCheckHandler = new timeCheckHandler();
public boolean onTouch(View v, MotionEvent event) {
//Log.v("ADAM", "ontouch: " + event.getAction());
boolean detectedUp = event.getAction() == MotionEvent.ACTION_UP;
if(event.getAction() == 0){
mSimpleGestureListener.onDown(event);
//Reset
mSimpleGestureListener.onTriggerJudge(false);
xChangingV = 0;
yChangingV = 0;
latestTrackedVelocityX = 0;
latestTrackedVelocityY = 0;
scrollInProgress = false;
firstJudge = false;
if (mVelocityTracker == null) {
// Retrieve a new VelocityTracker object to watch the velocity of a motion.
mVelocityTracker = VelocityTracker.obtain();
//// the following instruction resets the Time Check clock // the clock is first started
mTimeCheckHandler.sleep(timeCheckInterval);
} else {
// Reset the velocity tracker back to its initial state.
mVelocityTracker.clear();
hasRecycled = false;
}
//Log.v("ADAM", "Down");
}
else if (event.getAction() == 1) {
//Log.v("ADAM", "Up");
mSimpleGestureListener.onUp(event);
// Return a VelocityTracker object back to be re-used by others.
if(!hasRecycled){
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
hasRecycled = true;
//Reset
mSimpleGestureListener.onTriggerJudge(false);
xChangingV = 0;
yChangingV = 0;
latestTrackedVelocityX = 0;
latestTrackedVelocityY = 0;
scrollInProgress = false;
firstJudge = false;
}
//Add userMovement
//mVelocityTracker.addMovement(event);
}
else if (event.getAction() == 2) {
//Log.v("ADAM", "Scroll");
mVelocityTracker.addMovement(event);
// When you want to determine the velocity, call
// computeCurrentVelocity(). Then call getXVelocity()
// and getYVelocity() to retrieve the velocity for each pointer ID.
mVelocityTracker.computeCurrentVelocity(1000);
// Log velocity of pixels per second
xVelocity = mVelocityTracker.getXVelocity(0);
yVelocity = mVelocityTracker.getYVelocity(0);
if(Math.abs(xVelocity) > 20 || Math.abs(yVelocity) > 20){
scrollInProgress = true;
mSimpleGestureListener.onVelocityStop(false);
//mSimpleGestureListener.onTriggerJudge(false);
}
xChangingV = Math.abs(Math.abs(xVelocity) - latestTrackedVelocityX);
yChangingV = Math.abs(Math.abs(yVelocity) - latestTrackedVelocityY);
if(scrollInProgress && xChangingV>yChangingV + 100 && xChangingV + yChangingV > 100){
//Changing 1
mSimpleGestureListener.onTriggerJudge(true);
Log.e("Active","Active111");
//Changing 2
//firstJudge = true;
}
else if(yChangingV>xChangingV){
//Reset
mSimpleGestureListener.onTriggerJudge(false);
xChangingV = 0;
yChangingV = 0;
latestTrackedVelocityX = 0;
latestTrackedVelocityY = 0;
scrollInProgress = false;
//firstJudge = false;
}
if(!scrollInProgress && (latestTrackedVelocityX + latestTrackedVelocityY) > 1.4){
if(Math.abs(System.currentTimeMillis() - stopTime) > 200){
scrollInProgress = true;
}
}
long now = System.currentTimeMillis();
latestScrollEventTime = now;
}
else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
Log.v("ADAM", "Cancel2");
mSimpleGestureListener.onUp(event);
// Return a VelocityTracker object back to be re-used by others.
if(!hasRecycled){
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
hasRecycled = true;
}
}
else{
// Log.v("ADAM", "Else");
}
if (!mGestureDetector.onTouchEvent(event) && detectedUp) {
//Log.v("ADAM", "Cancel");
mSimpleGestureListener.onUp(event);
// Return a VelocityTracker object back to be re-used by others.
if(!hasRecycled){
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
hasRecycled = true;
}
return true;
}
return true;
// printTag(TAG,true,LOG_TYPE_I,event);
}
public boolean onSingleTapUp(MotionEvent event) {
//printTag(TAG,true,LOG_TYPE_I,event);
//mSimpleGestureListener.onUp(event);
return false;
}
@Override
public boolean onSingleTapConfirmed(MotionEvent event) {
//printTag(TAG,true,LOG_TYPE_I,event);
return false;
}
@Override
public boolean onDoubleTap(MotionEvent event) {
//printTag(TAG,true,LOG_TYPE_I,event);
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent event) {
//printTag(TAG,true,LOG_TYPE_I,event);
mSimpleGestureListener.onDoubleTap(event);
return false;
}
// ############ Time Check Handler ############
//Changing 1 - Trending
//private long timeCheckInterval = 100; // 检测间隔
//Changing 2 - Trending + StopJudge
private long timeCheckInterval = 16; // 检测间隔
private long scrollEndInterval = 20; // 滚动结束后保留时间
public long latestScrollEventTime;
private float latestTrackedVelocityX;
private float latestTrackedVelocityY;
public boolean scrollInProgress = false;
private float translationThereshold = 1.0f;
private long stopTime;
class timeCheckHandler extends Handler {
@Override
public void handleMessage(Message msg) {
long now = System.currentTimeMillis();
// Changing 2
// if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval) && Math.abs(Math.abs(xVelocity) - latestTrackedVelocityX) + Math.abs(Math.abs(yVelocity) - latestTrackedVelocityY) < translationThereshold ) {
// scrollInProgress = false;
//
// if(firstJudge){
// mSimpleGestureListener.onTriggerJudge(true);
// }
//
//
// //mSimpleGestureListener.onTriggerJudge(true);
//
// //Log.e("String2","trigger this;");
// //stopTime2 = now;
//
// }
// Changing 1
if (scrollInProgress && (now>latestScrollEventTime+scrollEndInterval) && Math.abs(Math.abs(xVelocity) - latestTrackedVelocityX) + Math.abs(Math.abs(yVelocity) - latestTrackedVelocityY) < translationThereshold ) {
scrollInProgress = false;
//mSimpleGestureListener.onTriggerJudge(true);
//Log.e("String2","trigger this;");
// stopTime = now;
}
stopTime = now;
latestTrackedVelocityX = Math.abs(xVelocity);
latestTrackedVelocityY = Math.abs(yVelocity);
if(scrollInProgress){
mSimpleGestureListener.onVelocityStop(false);
}else{
mSimpleGestureListener.onVelocityStop(true);
}
this.sleep(timeCheckInterval);
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
}
// ############ PrintTag ############
private void printTag(String tag,boolean show,int LOGTYPE,MotionEvent event){
final String suffix;
if(event == null){
suffix = "";
}
else{
int X = (int) event.getX();
int Y = (int) event.getY();
suffix = " - X: "+X+" Y: "+Y;
}
if(show){
if(LOGTYPE == 0){
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[3];//maybe this number needs to be corrected
String methodName = e.getMethodName();
Log.i(tag,methodName + suffix);
}
else if(LOGTYPE == 1){
StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
StackTraceElement e = stacktrace[3];//maybe this number needs to be corrected
String methodName = e.getMethodName();
Log.e(tag,methodName + suffix);
}
}
else{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment