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.
Related
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
In my new program I need objects that can be swiped to the side. I already have my animation, which is working and I tried to detect the swiping of the user in another class. The problem I have is that I don't know how to connect them. When the swipe gesture is correctly recognized a specific animation should start.
My AnimatedViewClass:
private Runnable r = new Runnable() {
#Override
public void run() {
if(continueAnimation) {
invalidate();
}
}
};
protected void onDraw(Canvas c) {
if (x<0) {
x = this.getWidth()/2-100;
y = this.getHeight()/2-100;
}
else {
x += xVelocity;
if ((x > this.getWidth() - ball.getBitmap().getWidth()) || (x < 0)) {
boolean continueAnimation = false;
}
}
c.drawBitmap(ball.getBitmap(), x, y, null);
if(continueAnimation)
{
h.postDelayed(r, FRAME_RATE);
}
else {
x = this.getWidth()-ball.getBitmap().getWidth();
}
}
My SwipeTouchListener:
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
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_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
result = true;
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
}
result = true;
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
}
You can add GestureDetector to your view class just like this, and replace your code inside onFling()
public class AnimatedViewClass extends View {
GestureDetector gestureDetector;
public AnimatedViewClass(Context context) {
super(context);
gestureDetector = new GestureDetector(getContext(), new GestureDetectorListener());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
private void onSwipeRight(){
// swipe right detected
// do stuff
invalidate();
}
private void onSwipeLeft(){
// swipe left detected
// do stuff
invalidate();
}
private class GestureDetectorListener extends
GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// onSwipeRight()
// onSwipeLeft()
return super.onFling(e1, e2, velocityX, velocityY);
}
#Override
public boolean onDown(MotionEvent e) {
return super.onDown(e);
}
}
private Runnable r = new Runnable() {
#Override
public void run() {
if(continueAnimation) {
invalidate();
}
}
};
protected void onDraw(Canvas c) {
if (x < 0) {
x = this.getWidth() / 2 - 100;
y = this.getHeight() / 2 - 100;
} else {
x += xVelocity;
if ((x > this.getWidth() - ball.getBitmap().getWidth()) || (x < 0)) {
boolean continueAnimation = false;
}
}
c.drawBitmap(ball.getBitmap(), x, y, null);
if (continueAnimation) {
h.postDelayed(r, FRAME_RATE);
} else {
x = this.getWidth() - ball.getBitmap().getWidth();
}
}
}
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
I needed help with this but didn't really find clear instructions. How to create a button that will fast forward and rewind current song on hold.
private Handler repeatUpdateHandler = new Handler();
public int mValue; //increment
private boolean mAutoIncrement = false; //for fast foward in real time
private boolean mAutoDecrement = false; // for rewind in real time
private class RptUpdater implements Runnable {
public void run() {
if( mAutoIncrement ){
mValue += 30; //change this value to control how much to forward
mediaPlayer.seekTo(getCurrentPosition()+ mValue);
repeatUpdateHandler.postDelayed( new RptUpdater(), 50 );
} else if( mAutoDecrement ){
mValue -= 30; //change this value to control how much to rewind
seekTo(getCurrentPosition()- mValue);
repeatUpdateHandler.postDelayed( new RptUpdater(), 50 );
}
}
}
btnPrev.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
v.setPressed(true);
mAutoDecrement = true;
repeatUpdateHandler.post( new RptUpdater() );
return false;
}
else if(event.getAction() == MotionEvent.ACTION_UP) {
v.setPressed(false);
if( (event.getAction()==MotionEvent.ACTION_UP || event.getAction()==MotionEvent.ACTION_CANCEL)
&& mAutoDecrement ){
mAutoDecrement = false;
}
return false;
}
return false;
}
});
btnNext.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
v.setPressed(true);
mAutoIncrement = true;
repeatUpdateHandler.post( new RptUpdater() );
return false;
}
else if(event.getAction() == MotionEvent.ACTION_UP) {
v.setPressed(false);
if( (event.getAction()==MotionEvent.ACTION_UP || event.getAction()==MotionEvent.ACTION_CANCEL)
&& mAutoIncrement ){
mAutoIncrement = false;
}
return false;
}
return false;
}
});
I am working on an application in which have two navigation button namely 'previous and next' which on tap load stories respectively. When i tap these buttons gently they work fine button when i tap next button to the last index continuously without any break then the previous button does not work or similarly when i start tapping previous button to the very first index i am unable to move forward.
Remember this only happens at the extreme cases, onClick is not called, don't know why.
My code is as follows, please help me out. Thanks in advance.
this the code of onClick, which works fine in all cases except the extreme cases, when buttons are not tapped gently.
public void onClick(View v) {
if (visible == true) {
Log.e("visible", "true");
return;
}
visible = true;
try {
Log.e("Now", "On Click");
pDialog = new ProgressDialog(StoriesListController.this);
pDialog.setIndeterminate(true);
pDialog.setIcon(R.drawable.icon_small);
pDialog.setCancelable(true);
if (isFavoriteList == true) {
pDialog.setMessage("Loading favorites...");
} else {
pDialog.setMessage("Loading data...");
}
pDialog.setTitle("Please wait");
pDialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
if (cancelableHeavyWorker != null) {
cancelableHeavyWorker.setHandler(null);
}
finish();
}
});
pDialog.show();
if (v == next) {
if (ind < items.size() - 1) {
ind++;
loadAndShowNextActivity();
}
} else if (v == previous) {
if (ind > 0) {
ind--;
loadAndShowNextActivity();
}
}
// realeaseMemoryIfneededofStory(ind);
} catch (Exception e) {
Log.e("Error", "--.OnClink Message" + e.toString());
e.printStackTrace();
}
}
Moreover, the boolean variable "visible" is being set to false in the callback function.
The Code of Call Back Function is as follows:
private void fetchTopStoryDetailCallback(Object resultVector) {
System.out.println("fetchTopStoryDetailCallback");
try {
Vector<?> v = (Vector<?>) resultVector;
boolean completedOrFailed = ((Boolean) v.elementAt(0)).booleanValue();
if (completedOrFailed == true) {
boolean slideshow = ((Boolean) v.elementAt(1)).booleanValue();
Object result = v.elementAt(2);
String res[] = (String[]) result;
if (slideshow) {
if (Utils.topStorySlidesArrayList != null && Utils.topStorySlidesArrayList.size() > 0) {
Intent articleActivityIntent = new Intent(this, SlideShowActivity.class);
articleActivityIntent.putExtra("storyData", (String[]) result);
articleActivityIntent.putExtra("back", back);
articleActivityIntent.putStringArrayListExtra("sid", slideids);
// articleActivityIntent.putExtra("contentType", )
articleActivityIntent.putExtra("addkey", ADDS_KEY);
showActivityInContoller(articleActivityIntent);
hidePrgressgingDailog();
} else {
hidePrgressgingDailog();
this.closeActivity = true;
showMessage("Error", "This story encounter an error while opening. Check your Internet Connection and try later");
}
} else {
if (res[3] != null && (!(res[3].equalsIgnoreCase("null")) && (!res[3].equals("")))) {
Intent slideshowActivtyIntent = new Intent(this, ArticleActivity.class);
slideshowActivtyIntent.putExtra("storyData", (String[]) result);
slideshowActivtyIntent.putExtra("back", back);
slideshowActivtyIntent.putExtra("addkey", ADDS_KEY);
showActivityInContoller(slideshowActivtyIntent);
hidePrgressgingDailog();
} else {
hidePrgressgingDailog();
this.closeActivity = true;
showMessage("Error", "This story encounter an error while opening. Check your Internet Connection and try later");
}
}
} else {
showMessage("Error", "This story encounter an error while opening. Check your Internet Connection and try later");
hidePrgressgingDailog();
}
} catch (Exception e) {
Log.e("StoriesController", "Message = " + e.toString());
e.printStackTrace();
}
finally {visible = false; }
}
this is how visiblity of the buttons is set...!!!!
private void adjustButtonsVisibility() {
try {
if (items.size() == 1) {
next.setEnabled(false);
next.setImageResource(R.drawable.navigator_next_disable);
previous.setEnabled(false);
previous.setImageResource(R.drawable.navigator_previous_disable);
//hidePrgressgingDailog();
return;
}
if (ind == 0) {
previous.setEnabled(false);
next.setEnabled(true);
previous.setImageResource(R.drawable.navigator_previous_disable);
next.setImageResource(R.drawable.story_next_arrow);
hidePrgressgingDailog();
} else if (ind > 0 && ind < items.size() - 1) {
previous.setEnabled(true);
next.setEnabled(true);
previous.setImageResource(R.drawable.story_previous_arrow);
next.setImageResource(R.drawable.story_next_arrow);
}
if (ind == items.size() - 1) {
previous.setEnabled(true);
next.setEnabled(false);
previous.setImageResource(R.drawable.story_previous_arrow);
next.setImageResource(R.drawable.navigator_next_disable);
hidePrgressgingDailog();
}
} catch (Exception e) {
Log.e("Error", "--,adjustButtonsVisibility Message = " + e);
e.printStackTrace();
}
}
Do this
if (ind == 0) {
previous.setEnabled(false);
previous.setImageResource(R.drawable.navigator_previous_disable);
next.setImageResource(R.drawable.story_next_arrow);
hidePrgressgingDailog();
}
else if (ind > 0 && ind < items.size() - 1) {
previous.setEnabled(true);
next.setEnabled(true);
previous.setImageResource(R.drawable.story_previous_arrow);
next.setImageResource(R.drawable.story_next_arrow);
}
else if (ind == items.size() - 1) {
previous.setEnabled(true);
next.setEnabled(false);
previous.setImageResource(R.drawable.story_previous_arrow);
next.setImageResource(R.drawable.navigator_next_disable);
hidePrgressgingDailog();
}