Android onFling MotionEvent not change - java

I'm working on a project and I'm using a ImageView that is moved in onScroll, I recently implemented an onFling to detect swipe but I just saw that when I swipe the picture, the two MotionEvents from the onFling get the same X value using getX(). But that doesn't happen when doing swipe outside the view.
Why can be this happening?
Is there a way to fix it?
Thanks!
This is what I'm trying to implement:
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
final int SWIPE_MIN_DISTANCE = 120;
final int SWIPE_MAX_OFF_PATH = 250;
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH){
return false;
}
// right to left swipe
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > Common.SWIPE_THRESHOLD_VELOCITY) {
if (Common.search_submissions_ID < Common.search_submissions.length()) {
Common.search_submissions_ID = Common.search_submissions_ID + 1;
finish();
startActivity(getIntent());
} else {
//Update
}
}
// left to right swipe
else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > Common.SWIPE_THRESHOLD_VELOCITY) {
if (Common.search_submissions_ID > 0) {
Common.search_submissions_ID = Common.search_submissions_ID - 1;
finish();
startActivity(getIntent());
}
}
} catch (Exception e) {
}
return false;
}
PD: SWIPE_THRESHOLD_VELOCITY = 4500

Related

Why is onFling() not working in ListView?

My app
schows a ListView. When swiping right or left the ListView for a the next or previous day should be loaded.
My solution
I tried to use the onFling() methode to detect a left or right swipe. It works fine if I swipe on the TextView above the ListView.
My problem
Swiping on the ListView doesn't trigger the onFling() methode. Probably because my ListView is scrollable. Any ideas on how to solve this?
OnFling()
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 100;
GestureDetector gestureDetector;
#Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(this, "Right to Left swipe", Toast.LENGTH_SHORT).show();
result = true;
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//left to right swipe
Toast.makeText(this, "Left to Right swipe", Toast.LENGTH_SHORT).show();
result = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
This sounds like an ideal use case for a ViewPager, which is meant for swiping left and right between different instances of the same fragment. The ViewPager handles all of the gestures for you.
See this guide and this guide for examples of how to set up a ViewPager.
This solved my problem:
gestureListener = new View.OnTouchListener(){
public boolean onTouch(View v, MotionEvent event){
return gestureDetector.onTouchEvent(event);
}
};
lv.setOnTouchListener(gestureListener);

The sensitivity of the finger swipe on the screen

I'm using GestureDetector.OnGestureListener to invoke method when user moves finger across the screen in the specified direction.
My problem - just move slightly and the method is called, I would like the user to move his finger a little more on the screen.
public class SwipeListener extends GestureDetector.SimpleOnGestureListener {
public static final int MIN_SWIPE_DISTANCE = 40;
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float xDiff = e1.getX() - e2.getX();
float yDiff = e1.getY() - e2.getY();
return resolveSwipe(xDiff, yDiff);
}
private boolean resolveSwipe(float xDist, float yDist) {
float yDistAbs = Math.abs(yDist);
float xDistAbs = Math.abs(xDist);
SwipeDirection swipeDirection;
if (yDistAbs > xDistAbs) {
if (yDistAbs < MIN_SWIPE_DISTANCE) {return false;}
swipeDirection = (yDist > 0) ? SwipeDirection.DOWN: SwipeDirection.UP;
} else {
if (xDistAbs < MIN_SWIPE_DISTANCE) {return false;}
swipeDirection = (xDist > 0) ? SwipeDirection.RIGHT: SwipeDirection.LEFT;
}
onSwipeEvent(swipeDirection);
return true;
}
private void onSwipeEvent(SwipeDirection swipeDirection) {
if (swipeDirection == SwipeDirection.UP) {
return;
}
if (swipeDirection == SwipeDirection.DOWN) {
return;
}
if (swipeDirection == SwipeDirection.LEFT) {
finger1()
return;
}
if (swipeDirection == SwipeDirection.RIGHT) {
finger1();
return;
}
}
public enum SwipeDirection {
UP, DOWN, LEFT, RIGHT
}
Is it possible? What should I change or add here?
You need to calculate as to what level of x-axis or y-axis you don't want to perform any action on swipe.
You have to declare minimum distance for swipe as private static final int SWIPE_MIN_DISTANCE = 160 may be it will help you Click here to implement it

MotionEvent.ACTION_UP is not called

i have a problem with an OnSwipeImageListener (implements OnTouchListener). I use the OnSwipeImageListener in two activities.
On the one activitiy on the ImageView is the OnTouchListener and an OnClickListener and on the other activity on the ImageView is only the OnTouchListener.
If i change return v.onTouchEvent(event) to true under the MotionEvent.ACTION_DOWN then the OnClickListener on the first activity doesn't work and in this way the Swipe of ImageView on the second activity doesn't work. I debugged some times and see that MotionEvent.ACTION_UP is never called.
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
dX = event.getX();
dY = event.getY();
return v.onTouchEvent(event);
case MotionEvent.ACTION_UP:
uX = event.getX();
uY = event.getY();
float deltaX = dX - uX;
float deltaY = dY - uY;
// horizontal
if(Math.abs(deltaX) > MIN_DISTANCE) {
//Left to right
if(deltaX < 0) {
this.onLeftToRight();
return v.onTouchEvent(event);
} else if (deltaX > 0) {
this.onRightToLeft();
return v.onTouchEvent(event);
}
else {
//Swipe too short
return v.onTouchEvent(event);
}
}
// vertical
if (Math.abs(deltaY) > MIN_DISTANCE) {
if(deltaY < 0) {
this.onTopToBottom();
return v.onTouchEvent(event);
} else if (deltaY > 0) {
this.onBottomToTop();
return v.onTouchEvent(event);
}
else {
//Swipe too short
return v.onTouchEvent(event);
}
}
}
return v.onTouchEvent(event);
}
If you want to get the ACTION_UP, you should hijack the ACTION_DOWN.
Instead of returning "v.onTouchEvent(event)", return "true" when you are just handling the ACTION_DOWN.

onFling() 2D Animation Issue

I'm trying to run a very simple 2D animation when I fling an image view. I have 2 activities involved in this.
The GameCanvas
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
{
if(GameWindow.getContext() == null)
return false;
if((e1.getY() >= GameWindow.getHeight()) && (e1.getY() <= GameWindow.getBottom()))
{
try
{
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left slap
if((e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) && (Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY))
{
slappingLeft = true;
//Animate Slap
GameWindow.update();
if(!running)
running = true;
}
else if ((e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) && (Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY))
{
slappingRight = true;
//Animate Slap
GameWindow.update();
if(!running )
running = true;
}
}
catch (Exception e)
{
//nothing
}
}
slappingLeft = slappingRight = running = false;
return true;
}
And the GameWindow
private RefreshHandler mRedrawHandler = new RefreshHandler();
class RefreshHandler extends Handler
{
#Override
public void handleMessage(Message msg) {
GameWindow.this.update();
GameWindow.this.invalidate();
}
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public void update()
{
//animate slap
if(GameCanvas.slappingLeft)
{
for(int i = 0; i < 500; i+=100)
{
GameCanvas.SlapLeft();
mRedrawHandler.sleep(100);
}
GameCanvas.SetImage();
//this.invalidate();
}
else if(GameCanvas.slappingRight)
{
for(int i = 0; i < 500; i+=100)
{
GameCanvas.SlapImage();
mRedrawHandler.sleep(100);
}
GameCanvas.SetImage();
//this.invalidate();
}
}
I would greatly appreciate if anyone helps me figure this problem out. I have tried many different approaches to this problem.
I just want to show the SlapImage for half a second, then revert back to the normal image till onFling is called again.
If you would like to see SetImage(), SlapLeft(), and SetImage(), let me know!
Thanks very much in advance!
EDIT
GameCanvas is not a Canvas obj. Its an activity that setsContentView(R.layout.game_canvas)
GameWindow is a custom ImageView
I've found the problem in your code. Maybe it is influence on the result but I'm not sure. The problem is that you should use brackets in your if statements because operator && has higher priority then comparison operators. So your code should look in the following way:
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
{
if(GameWindow.getContext() == null)
return false;
if((e1.getY() >= GameWindow.getHeight()) && (e1.getY() <= GameWindow.getBottom()))
{
try
{
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left slap
if((e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) && (Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY))
{
slappingLeft = true;
//Animate Slap
GameWindow.update();
if(!running)
running = true;
slappingLeft = false;
}
else if ((e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) && (Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY))
{
slappingRight = true;
//Animate Slap
GameWindow.update();
if(!running)
running = true;
slappingRight = false;
}
}
catch (Exception e)
{
//nothing
}
}
running = false;
return false;
}
I don't know if this influence on the logic of your code but it seems to me that yes.
After some consideration, i decided to implement this solution. I think it works fairly well.
I'm still not sure why my previous way didn't work. If anyone would still like to elaborate I would appreciate.
GameCanvas. I created this thread.
resetSlap = new Thread()
{
public void run()
{
while(true)
{
try
{
Thread.sleep(500);
GameWindow.post(new Runnable()
{
public void run()
{
GameWindow.setImageBitmap(images[0]);
GameWindow.postInvalidate();
}
});
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
Baiscally, every half-second I want to reset the image back to normal
Then in the OnFling I wrote
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
{
if(GameWindow.getContext() == null)
return false;
if((e1.getY() >= GameWindow.getHeight()) && (e1.getY() <= GameWindow.getBottom()))
{
try
{
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left slap
if((e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) &&
(Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY))
{
slappingLeft = true;
//Animate Slap
SlapLeft();
SlapSound();
if(voice.nextInt(10) < 3)
{
Voice.start();
}
}
// left to right slap
else if ((e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) &&
(Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY))
{
slappingRight = true;
//Animate Slap
SlapImage();
SlapSound();
if(voice.nextInt(10) < 3)
{
Voice.start();
}
}
}
catch (Exception e)
{
//nothing
}
}
slappingLeft = slappingRight = false;
return true;
}
Basically, if I was slapping left I would call Slap left and wait for the thread to reset and if i was slapping right I would call Slap Right and wait for the thread to reset.
This answer works well for my situation.. I hope this helps :D
Thank you all for your help.

Event for swipe left/right

Im having a calendar and I want to make it possible to swipe left/right and switch months.
Is there any listener to swipe left/right?
Thank you!
You can user a SimpleOnGestureListener like the example below: (obviously, replace the toast with the actual code that move to next/previous month)
public class SelectFilterActivity extends Activity implements OnClickListener
{
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* ... */
// Gesture detection
gestureDetector = new GestureDetector(new MyGestureDetector());
gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
};
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
// nothing
}
return false;
}
}
Then you attach it to your view:
// Do this for each view added to the grid
view.setOnClickListener(SelectFilterActivity.this);
view.setOnTouchListener(gestureListener);
SimpleOngestureListener can catch onFling ;
you can override this to catch swipes .
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//do your stuff
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
//do your stuff
}
} catch (Exception e)
{
// nothing
}
return false;
}

Categories

Resources