When I touch the screen and move my finger I do something (pullanimation1 and 2) and when I release the screen I do something else (fireanimation1 and 2). Sometimes, the user might touch the screen while pullAnimation or fireAnimation is running, I get errors as the animation then run several times. I would like to make sure the animations won't run more then once when the user touch again the screen.
NB: pullAnimation1 and 2, fireAnimation 1 and 2 are AnimationDrawable
Here is what I've done :
image2.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
boolean bool=false;
boolean bool2=true;
int action = arg1.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
if (bool2) {
startAnimation(pullAnimation1,pullAnimation2);
bool=true;
}
break;
case MotionEvent.ACTION_MOVE:
if (bool2==true){
Log.w("GAMEACTIVITY","move");
bool=true;
bool2=false;
}
break;
case MotionEvent.ACTION_UP:
startAnimation(fireAnimation1,fireAnimation2);
bool=false;
doPhotoTask();
bool2=false;
break;
}
return bool;
}
});
I think you should be able to use the hasStarted() and hasEnded() methods to determine if your animation is currently going. See the docs for more
Some if statement like this might work:
if((fireAnimation1.hasStarted() == false) || (fireAnimation1.hasEnded == true()){
startAnimation(fireAnimation1, fireAnimation2);
}
I imagine you may also need to use reset() after it is done playing in order or the methods to return proper values next time touch happens.
EDIT:
AnimationDrawable has an isRunning() method, which makes it even easier than View animations.
if(fireAnimation1.isRunning() == false){
startAnimation(fireAnimation1, fireAnimation2);
}
Related
I apologise for the somewhat noobish question.
I've tried googling it, searching this site and the android developer site, yet didn't manage to find an answer.
I'm looking for a listener that differentiates between up and down events. Currently I'm using OnTouchListener, but it gets triggered very fast, causing a noticable lag, even when I immediately return after an event that is not Down and Up.
I've also tried OnClickListener, but it seems to only get triggered when you lift your finger up, rather than have seperate events for down click and up click like I need.
Would appreciate some help,
Thanks!
YourBtn.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
if(event.getAction() == MotionEvent.ACTION_UP){
//do stuff
}
else if(event.getAction() == MotionEvent.ACTION_DOWN){
//do stuff
}
else if(event.getAction() == MotionEvent.ACTION_CANCEL){
//do stuff
}
return true; //return false can be used it depends
}
});
P.S: it can be: a button, a textview, an imageview or any UI element
I strongly recommend to always add ACTION_CANCEL to avoid any misbehaviours or crashes
See this:
https://developer.android.com/training/graphics/opengl/touch.html
Override the following method on your activity, then you can treat each case, when the user touch the screen, and when he take of his finger.
#Override
public boolean onTouchEvent(MotionEvent e) {
// MotionEvent reports input details from the touch screen
// and other input controls. In this case, you are only
// interested in events where the touch position changed.
float x = e.getX();
float y = e.getY();
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
// do your stuff
break;
case MotionEvent.ACTION_UP:
// do your stuff
break;
}
return true;
}
You should look at GestureDetector to simplify your touch event handling.
I have
RelativeLayout
A---BIG IMAGE
B---MEDIUM IMAGE
C---SMALL IMAGE
The picture is looking like this
I have used below java code
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
// LEFT
case R.id.tblLOne:
System.out.println("IMG_L_A");
playBeep(TABLA_L_BIG);
changeLeftDrum();
break;
case R.id.tblLTwo:
System.out.println("IMG_L_B");
playBeep(TABLA_L_MID);
changeLeftDrum();
break;
case R.id.tblLThree:
System.out.println("IMG_L_C");
playBeep(TABLA_L_SMALL);
changeLeftDrum();
break;
return false;
}
return true;
}
Problem is that whenever I click on small (BLACK) Image
I got following output
IMG_L_A
IMG_L_B
IMG_L_C
Whenever I click on Middle Image I got
IMG_L_A
IMG_L_B
On OuterImage big image
IMG_L_A
Why I am getting it's all behind ImageView's OnTouch Method
It is working perfect with onClick but not with OnTouch
It's because the views are stacked on top of each other.
The important point here is to know the importance of the Boolean flag that you return from your onTouchListener. The boolean flag tells android if the event was consumed or not.
Suppose, you touch tblRthree, the case R.id.tblLThree executes, but then since you return false, it appears to android that the event was not consumed and this event bubbles up to the tblRTwo view which is just behind tblRthree view, which executes the same listener for the case R.id.tblLTwo but then again you return false so, it bubbles up to view tblROne and all three cases execute.
You should return true whenever you consume the event, and false when you don't.
onTouch method will be called in multiple events, all you need is to check whether it is MotionEvent.ACTION_DOWN or not.
So, it will look something like this:
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction()!=MotionEvent.ACTION_DOWN)
{
return false;//we are not going to handle it
}
switch (v.getId()) {
// LEFT
case R.id.tblLOne:
System.out.println("IMG_L_A");
playBeep(TABLA_L_BIG);
changeLeftDrum();
break;
case R.id.tblLTwo:
System.out.println("IMG_L_B");
playBeep(TABLA_L_MID);
changeLeftDrum();
break;
case R.id.tblLThree:
System.out.println("IMG_L_C");
playBeep(TABLA_L_SMALL);
changeLeftDrum();
break;
}
return true;//we have handled it
}
I have a view in my Android app that should be updated constantly when the screen is being pressed. Most listeners I found only invalidate the view once when the user touches the screen for the first time, or when the user removes his hand from the screen.
Is there such a thing as a listener that is constantly triggered as long as the screen is touched ? Or is there any other way to do this ? I know, that sounds like something really simple, but I haven't found a way to do it.
Override onTouch() and set a flag in ACTION_DOWN. As long as ACTION_UP isn't called after that, the user is touching the screen.
boolean pressed = false;
#Override
public boolean onTouch(View v, MotionEvent event) {
//int action = event.getAction();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
pressed = true;
break;
case MotionEvent.ACTION_MOVE:
//User is moving around on the screen
break;
case MotionEvent.ACTION_UP:
pressed = false;
break;
}
return pressed;
}
Ok... in my app i update the layout on MotionEvent.ACTION_DOWN and then i check the motion event coordinates to locate my buttons. I can show a toast when finger is released on different buttons. The problem is i need a long touch on my buttons to call another action without conflicting with the MotionEvent.ACTION_UP. Implemented a long click handler but since i don't 'click' its not working. Hope you guys understand my problem.
Whats the best way to get my app working as intended?
My class implements OnTouchListener, OnGestureListener
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
// UPDATE LAYOUT
break;
case MotionEvent.ACTION_UP:
// GET BUTTON X Y
if (x and y match the button location){
// DO ACTION
}else{
// DO NOTHING
}
// CHANGE LAYOUT TO INITIAL STATE
break;
case MotionEvent.ACTION_MOVE:
break;
}
return false;
mybutton.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
// DO STUFF
return true;
}
});
}
just try to return false in your onTouch(...) method and use onLongClickListener(...) as usual
My class extends View and I need to get continuous touch events on it.
If I use:
public boolean onTouchEvent(MotionEvent me) {
if(me.getAction()==MotionEvent.ACTION_DOWN) {
myAction();
}
return true;
}
... the touch event is captured once.
What if I need to get continuous touches without moving the finger?
Please, tell me I don't need to use threads or timers. My app is already too much heavy.
Thanks.
Use if(me.getAction() == MotionEvent.ACTION_MOVE). It's impossible to keep a finger 100% completely still on the screen so Action_Move will get called every time the finger moves, even if it's only a pixel or two.
You could also listen for me.getAction() == MotionEvent.ACTION_UP - until that happens, the user must still have their finger on the screen.
You need to set this properties for the element
android:focusable="true"
android:clickable="true"
if not, just produce the down action.
Her is the simple code snippet which shows that how you can handle the continues touch event. When you touch the device and hold the touch and move your finder, the Touch Move action performed.
#Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
if(isTsunami){
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Write your code to perform an action on down
break;
case MotionEvent.ACTION_MOVE:
// Write your code to perform an action on contineus touch move
break;
case MotionEvent.ACTION_UP:
// Write your code to perform an action on touch up
break;
}
}
return true;
}
Try this. It works to me:
public static OnTouchListener loadContainerOnTouchListener() {
OnTouchListener listener = new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
LinearLayout layout = (LinearLayout)v;
for(int i =0; i< layout.getChildCount(); i++)
{
View view = layout.getChildAt(i);
Rect outRect = new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
if(outRect.contains((int)event.getX(), (int)event.getY()))
{
Log.d(this.getClass().getName(), String.format("Over view.id[%d]", view.getId()));
}
}
}
Remember: the listener you´ll set must be a container layout (Grid, Relative, Linear).
LinearLayout layout = findViewById(R.id.yourlayoutid);
layout.setOnTouchListener(HelperClass.loadContainerOnTouchListener());
This might help,
requestDisallowInterceptTouchEvent(true);
on the parent view, like this -
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
view.getParent().requestDisallowInterceptTouchEvent(true);
switch(motionEvent.getAction()){
}
return false;
}
I was making a game with a custom view used as a thumb control. . . here is what I did
float x = 0, y = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
x = event.getX();
y = event.getY();
// handle touch events with
switch( event.getActionMasked() ) {
case MotionEvent.ACTION_DOWN :
if(cont)
{
// remove any previous callbacks
removeCallbacks(contin);
// post new runnable
postDelayed(contin, 10);
}
invalidate();
return true;
case MotionEvent.ACTION_MOVE :
if(!cont && thumbing != null)
{
// do non-continuous operations here
}
invalidate();
return true;
case MotionEvent.ACTION_UP :
// set runnable condition to false
x = 0;
// remove the callbacks to the thread
removeCallbacks(contin);
invalidate();
return true;
default :
return super.onTouchEvent(event);
}
}
public boolean cont = false;
// sets input to continuous
public void set_continuous(boolean b) { cont = b; }
public Runnable contin = new Runnable()
{
#Override
public void run() {
if(x != 0)
{
// do continuous operations here
postDelayed(this, 10);
}
}
};
A quick note however, make sure in your main activity that is calling this view removes the callbacks manually via the onPause method as follows
#Override
protected void onPause() {
if(left.cont) left.removeCallbacks(left.contin);
if(right.cont) right.removeCallbacks(left.contin);
super.onPause();
}
That way if you pause and come back touch events aren't being handled twice and the view is free from it's thread's overhead.
** tested on Samsung Galaxy S3 with hardware acceleration on **
All these answer are partially correct but they do not resolve in the right way the problem.
First of all, for everyone out there that decide to track when the event is ACTION_MOVE. Well that works only guess when? When user move his finger, so could if you decide to implement a custom thumb control is okay but for a normal custom button that's not the case.
Second, using a flag inside ACTION_DOWN and check it in ACTION_UP seems the logic way to do it, but as Clusterfux find out if you implement a while(!up_flag) logic you get stuck into troubles ;)
So the proper way to do it is mentioned here:
Continuous "Action_DOWN" in Android
Just keep in mind that if the logic you're going to write during the continuous press has to modify the UI in some way, you have to do it from the main thread in all the other cases it's better use another thread.
You can use the below code snippet as a reference in which I used the background to detect if the screen is held or not...
Main_Layout.setOnTouchListener(new View.OnTouchListener() {
#SuppressLint("ResourceAsColor")
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
Main_Layout.setBackgroundColor(R.color.green);
event.setAction(MotionEvent.ACTION_DOWN);
break;
default:
Main_Layout.setBackgroundColor(R.color.blue);
break;
}
return false;
}
});