I've been learning android for almost a month, and I want to make a simple game with a custom class that extends from View, and it's included on main_activity.xml. In Main Activity.class I create an instance of the View, and control the movement of the sprite on the GameView with buttons, so each button has a method that control sprite's movement like this:
public void move_up(View v){
gameview.sprite.move(Dir.UP);}
The problem is that it only works when the button is released, and it's executed one time. I want the method to be executed while the botton is pressed but I can't figure out how to do this.
I'm assuming by the name of your method that you're adding the onClick property to the xml layout file in order to handle the event. While this may seem convenient at first it will not give you what you need.
Instead, you should implement the OnTouchListener which gives you information about what touch event is currently happening, in your case you'd want to handle the ACTION_DOWN action:
findViewById(R.id.btn_up).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
gameview.sprite.move(Dir.UP); //Or whatever
return true; //In case you wan to handle ACTION_UP
}
return false;
}
});
Although you could make your Activity implement the listener and handle multiple buttons there. This is achieved simply by telling your activity to implement OnTouchListener, imeplementing the method onTouch as in the code above but instead as a method of your activity.
And the resulting set, would be simplified to findViewById(R.id.btn_up).setOnTouchListener(this); where R.id.btn_up is the id you've defined in the xml file.
This would make it start moving when they press, instead of when they release, if what you want is to make it move until they release (which would make sense), do something like:
if(event.getAction() == MotionEvent.ACTION_DOWN){
gameview.sprite.move(Dir.UP); //Or whatever
return true; //In case you wan to handle ACTION_UP
}else
if(event.getAction() == MotionEvent.ACTION_UP){
gameview.sprite.stop(); //Or whatever you call the stop method
return false;
}
Related
Is it possible to know in a ListView if a item is pressed / touched (but not clicked) and know which?
I tried with "OnTouchListener" but without success (I can intercept UP and Down events on the ListView but not on the elements).
I tried also "OnItemLongClickListener" but I have to wait when I want information immediately.
Do you have an idea ?
Thank you in advance.
Edit (solution) :
I put the following code in my adapter in the item view.
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
image.setImageResource(R.drawable.image2);
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
image.setImageResource(R.drawable.image1);
}
return true;
}
});
And now, when I touch an item, the picture becomes "image2" and when I do not touch the screen, it returns to "image1".
But there is a problem, if I press an item (the image2 appears well) and I move my finger in the list view and I do not touch the screen, it stays on for the image2, "MotionEvent.ACTION_UP" could not execute.
Do you have any idea how to do that as soon as I do not touch the screen, it must return on image1?
Thank you for your help.
You can set SetOnTouchListener to item view when your adapter create it.
you just try yo implement the Listener then you can override the function or please add your rough work part
I have a layout in my activity with some UI elements in it. I want to handle long press for the whole activity.Also I need to handle click events for all the UI events seperately. How can I do it? Pls help.
your class can use the interface onLongClickListener
like yourclass extends Activity implements View.OnLongClickListener which has the method that get notified on long press.
Note: Don't forget to set yourView.setOnLongClickListener(this); for all the views you need
Rename your layout just the biggest of(linear layout, relative layout or...) in xml file and use this coDe
Layout ly=(Layout) findVewById(R.id.yourlayout);
ly.setOnLongClickListener (new. Onlongclicklistener(){
#Override
public boolean onTouchEvent(MotionEvent event) {
//do something
}
}
Example of code an Activity subclass can use to implement special actions for a long press
CALL key:
#Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_CALL) {
// a long press of the call key.
// do our work, returning true to consume it. by
// returning true, the framework knows an action has
// been performed on the long press, so will set the
// canceled flag for the following up event.
return true;
}
return super.onKeyLongPress(keyCode, event);
}
Check http://android-developers.blogspot.in/2009_12_01_archive.html
I have a Linear Layout that has a Button and a TextView on it. I have written a OnTouchEvent for the activity. The code works fine if I touch on the screen, but if I touch the button the code does not work. What is the possible solution for this?
public boolean onTouchEvent(MotionEvent event) {
int eventaction=event.getAction();
switch(eventaction)
{
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
}
return true;
}
The problem is the order of operations for how Android handles touch events. Each touch event follows the pattern of (simplified example):
Activity.dispatchTouchEvent()
ViewGroup.dispatchTouchEvent()
View.dispatchTouchEvent()
View.onTouchEvent()
ViewGroup.onTouchEvent()
Activity.onTouchEvent()
But events only follow the chain until they are consumed (meaning somebody returns true from onTouchEvent() or a listener). In the case where you just touch somewhere on the screen, nobody is interested in the event, so it flows all the way down to your code. However, in the case of a button (or other clickable View) it consumes the touch event because it is interested in it, so the flow stops at Line 4.
If you want to monitor all touches that go into your Activity, you need to override dispatchTouchEvent() since that what always gets called first, onTouchEvent() for an Activity gets called last, and only if nobody else captured the event. Be careful to not consume events here, though, or the child views will never get them and your buttons won't be clickable.
public boolean dispatchTouchEvent(MotionEvent event) {
int eventaction=event.getAction();
switch(eventaction) {
case MotionEvent.ACTION_MOVE:
reg.setText("hey");
break;
default:
break;
}
return super.dispatchTouchEvent(event);
}
Another option would be to put your touch handling code into a custom ViewGroup (like LinearLayout) and use its onInterceptTouchEvent() method to allow the parent view to steal away and handle touch events when necessary. Be careful though, as this interaction is one that cannot be undone until a new touch event begins (once you steal one event, you steal them all).
HTH
Let me add one more comment to this excellent post by #Devunwired.
If you've also set an onTouchListener on your View, then its onTouch() method will be called AFTER the dispatch methods, but BEFORE any onTouchEvent() method, i.e. in between no.3 and no.4 on #Devunwired's answer.
Try to set the descendantFocusability attribute of your layout to blocksDescendants
Activity::onTouchEvent will be called only when non of the views in the Activity WIndow consumes/handles the event. If you touch the Button, the Button will consume the events, so the Activity won't be able to handle it.
Check out following articles for more about Android Touch Event handling pipeline.
http://pierrchen.blogspot.jp/2014/03/pipeline-of-android-touch-event-handling.html
you can also try onUserInteraction():
#Override
public void onUserInteraction(){
//your code here
super.onUserInteraction();
}
works well for me!
RecyclerView list_view = findViewById(R.id.list_view);
list_view.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener(){
#Override
public boolean onInterceptTouchEvent(#NonNull RecyclerView rv, #NonNull MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
Log.i("Hello", "World");
return false;
}
});
use public boolean dispatchTouchEvent(MotionEvent event) instead on onTouchEvent()
Problem description:
I have a TextView on a RelativeLayout and I want to color it red when the user touches it, and go on another page when he clicks on it.
So I tried to set an OnClickListener to do the click, and an OnTouchListener to implement the touch function (MotionEvent.ACTION_DOWN) but this combination doesn't work, because OnTouchListener makes OnClickListener non-functional (don't know why).
On forums people say that we can implement the OnClick by the OnTouch MotionEvent.ACTION_UP, but this one can be triggered out of my TextView layout (the TextView gonna be clicked if you press it and drag your finger out of him to release) and this is not the desired behavior because I want:
click = press + release on the TextView.
Can someone give me a solution for this please?
you may call View.performClick() when action_up. Hope it helps.
your_txtView.setOnClickListener(new TextView.OnClickListener(){
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
your_txtView.setOnTouchListener(new TextView.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getAction()) {
} else if (MotionEvent.ACTION_UP == event.getAction()) {
v.performClick();
}
return true;
}
});
Adel, is the problem with the first click, or you don't get any click at all?
There is this issue if you have multiple clickable layout you don't get any click events for the first. That's because it makes it first selected and then you get the click event, try the below code.
private class CustomTouchListener implements OnTouchListener {
#Override
public boolean onTouch(View v, MotionEvent event) {
TextView tv = (TextView) v.findViewById(R.id.single_line_text);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
tv.setTextColor(COLOR_WHEN_PRESSED);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
tv.setTextColor(COLOR_WHEN_RELEASED);
// Action of click goes here
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
tv.setTextColor(COLOR_WHEN_RELEASED);
// To handle release outside the layout region
}
return false;
}
}
This is working in my current implementation if you set the touch listener for your layout.
You also need to set below on your layout
android:focusable="true"
android:focusableInTouchMode="true"
android:clickable="true"
Hope it helps!!!
EDIT: Additionally, there should be a flag in both DOWN and UP. Set it in DOWN and check if its set in UP. This will avoid a bug where user might tap anywhere in the screen and then hover on your textview and release it.
Had the same problem. Solved it by returning false from ACTION_MOVE. I've been fighting with it for few hours, trying various things, but seems like i've kept overlooking this little issue... And now it makes sense. When you return true from onTouch, futher processing is stopped, so that OnClickListener is not aware of any movements and triggers onClick even after pointer have moved outside of view.
Im working on an app with a friend and i want the button to visually press by changing the background and vibrating and then when released it does whatever that button is supposed to do.
the buttons i have right now only have an onclick method but i want it vibrate when touched and execute their function when clicked
i know of the ontouch and onclick methods but i cant seem to use them togetherand have already implemented both onclicklistener and ontouchlistener
how might i manage this.
You could do this by only using the OnTouchListener:
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
/* Change your button background and vibrate */
}
else if (event.getAction() == MotionEvent.ACTION_UP) {
/* Button's functionality */
}
return true;
}
Hope it helps.