Alternative to make an action when pressing/realising a button, android - java

I want to make an application with 9 buttons for android 4.0, I need each of the buttons to call a method when pressed and another method when released.
I'm kind of surprised there's not a really straight-forward method to accomplish what I just described but thanks to some questions and answers I read on stackoverflow I managed to accomplish what I need by adding a listener in each of the buttons, as shown for one of the buttons in the next code.
buttonUp.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
buttonUpPressed();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
buttonUpReleased();
}
return true;
}
});
I want to know if there's an alternative to accomplish this behavior without having to add a listener for every button. I see that as a waste of resources and a lot of coding. I can't imagine if I eventually have to add more buttons.
So any help would be appreciated.

implements your class with OnTouchListener
Button a,b;
Button[] bArray = {a,b};
for (int i = 0; i < bArray.length; i++) {
bArray[i].setOnTouchListener(this)
}
after that add unimplemented method
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN){
switch (v.getId()) {
case R.id.button1:
break;
default:
break;
}
}
else if(event.getAction() == MotionEvent.ACTION_UP){
switch (v.getId()) {
case R.id.button1:
break;
default:
break;
}
}
return false;
}
i hope you'll like my logic :)

You can add all the buttons to an array or ArrayList and then define a listener field in your class.
OnTouchListener oclButtons = new OnTouchListener(...);
Then you can add the same listener to all the Buttons in the ArrayList.
for (Button b : listOfButtons) {
b.setOnTouchListener(oclButtons);
}
An alternative to setting IDs for each Button is to get/set tags (since each view needs a unique ID). Your listener can determine which button was touched by using v.getTag().

Related

Drag a view onLongClick and start activity onClick

I'm banging my head with this problem which probably is simple but since I'm new to this topic I somehow haven't been able to figure it out yet.
I've successfully implemented dragging a view with onTouch method. I've also successfully implemented onLongClick and onClick methods. But both of these functionalities were implemented separately.
The problem, like the title says is when I want to join these functionalities. I want the onTouch method to be called when a user long clicks a view and I want a new activity to start when a user clicks a view.
Here is the pseudo code:
public class Website extends AppCompatActivity implements View.OnTouchListener{
TextView longpress;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_website);
longpress = (TextView) findViewById(R.id.longpress);
longpress.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view){
//I don't really know how to do this part
onTouch(View view, Motion Event event);
return true;
}
});
longpress.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
//Code for new activity comes here (I know how to do this part)
}
});
}
public boolean onTouch(View view, MotionEvent event) {
switch(event.getAction(){
case MotionEvent.ACTION_DOWN:
//Save initial coordinates of view <-- view.getX(), view.getY()
break;
case MotionEvent.ACTION_MOVE:
//Calculate dX and dY and setX and Y of the view (move view)
break;
case MotionEvent.ACTION_UP:
//If view is certain distance away from initial points do something
break;
}
}
}
Like I said, onTouch works on itself if I don't try to call it from onLongClick method. If I try to call onTouch(View view, MotionEvent event) from onLongClick method the problem occurs because onLongClick only receives one out of two arguments onTouch method should receive (onLongClick only receives view argument but it should also receive event argument).
Maybe I'm trying to do this in a totally wrong way but I have been looking at some documentation e.g. https://developer.android.com/training/gestures/ but still won't get an idea what to do.
(I would like to have a similar functionality to notifications on android phones)
So I've come to a solution which might or might not be a good one but for now it serves my functionality. If someone has a better solution and thinks mine is bad in some way please say so.
Here is the code:
boolean flag;
public boolean onTouch(View view, MotionEvent event){
int action = event.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_DOWN){
//do something on a down press
flag = true;
return true;
}
if(action == MotionEvent.ACTION_UP && flag == true){
//do something if we move finger away from screen we
//didn't move the view first
return true;
}
if(action == MotionEvent.ACTION_UP && flag == false){
//do something if we move finger away from screen and we moved
//the view before we moved the finger away from screen
}
if(action == MotionEvent.ACTION_MOVE){
//do something when moving the view
flag = false;
}

Need a method called after on touch has completed

In our android program we are having trouble getting a method to call at the right time. We have an ontouchlistener and we tried to have it called on release, meaning the other functions would proceed it. However, it appears everything in "ontouch" happens at the same time. How do we get this other method to be called after the others have completed?
#Override
public boolean onTouch(View v, MotionEvent event) {
Tile touchedTile = (Tile) v;
if (touchedTile.isEmpty() || !touchedTile.isInRowOrColumnOf(emptyTile)) {
return false;
}
else {
mediaPlayer.start();
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
movedTile = touchedTile;
currentMovement = getTilesBetweenEmptyTileAndTile(movedTile);
//movedTile.numberOfMoves = 0;
}
else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
if (lastDragPoint != null) {
followFinger(event);
}
lastDragPoint = new PointF(event.getRawX(), event.getRawY());
}
else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
currentMovement = getTilesBetweenEmptyTileAndTile(movedTile);
if (lastDragMovedAtLeastHalfway() || isClicked()) {
animateTilesToEmptySpace();
checkMatch();
}
else {
animateTilesBackToOrigin();
}
currentMovement = null;
lastDragPoint = null;
movedTile = null;
}
return true;
}
}
Why don't you try to extend the view where you're setting the OnTouchListener and override the method onTouchEvent from that view. Call the super, after invoke your own methods, that way you ensure that they will be triggered before the onTouchLister. Let me know if that did the trick.
If you're looking for a complex listener, you should look at MotionEvent, So for MotionEvent.ACTION_UP the doc says:
... A pressed gesture has finished, the motion contains the final release location as well as any intermediate points since the last down or move event....
There is a lot of info about it.
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// I just put my finger on the view
return true;
case MotionEvent.ACTION_MOVE:
// I am moving my finger over the screen
return true;
case MotionEvent.ACTION_UP:
// I have just released my finger from the screen
return true;
default:
return super.onTouchEvent(event);
}
}
EDIT: looks like you're trying to make a jigsaw puzzle app with one empty cell.
Considering you must be using an animator object, u also must have registered an on animate update listener. Shouldn't you put the checkMatch() method inside it so that it gets called whenever the animation ends, since a match will occur only after the user moves tiles?

Holding down a button for repeated action -- is there an android:onClick for holds? (in XML files)

Hopefully the question says it all... I've been searching the web for an easy solution, I'm surprised to see there isn't? I expected this to be a basic functionality that I could just add into the XML file? Alternatives are welcome, but I already know they're out there. I just want to know if this simple method is possible (couldn't seem to find anything in the documentation but who knows)
There isn't any default way of doing this. But it's fairly easy accomplishing this using the onTouch() Event. The following code will repeat a task every 0.5 sec starting the time you touch a button. The tasks will be cancelled whenever you release the button.
Handler repeatedHandler = new Handler();
Runnable newRunnable = new Runnable() {
#Override
public void run() {
//Code for the task that needs to be repeated
//...
//...
repeatedHandler.postDelayed(newRunnable, 500);
}
};
button.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
repeatedHandler.postDelayed(newRunnable, 500);
break;
case MotionEvent.ACTION_UP:
repeatedHandler.removeCallbacks(newRunnable);
break;
}
}
});
you can set OnLongClickListener like
btn.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
---code here---
return false;
}
});
or you can set onTouchListner on button
btn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction())
{
case MotionEvent.ACTION_UP:
---code here---
break;
case MotionEvent.ACTION_DOWN:
---code here---
break;
}
});
I don't know how to set onLongClickListner from xml
You can use OnLongClickListener() for Button
Follow this link to read more about it...
View.OnLongClickListener
Example :
Examples for android.view.View.OnLongClickListener

Which items are sensitive to MotionEvent.ACTION_MOVE?

I am setting OnTouchListener to a Button, I can check if motion type is MotionEvent.ACTION_MOVE. On the other hand if it is TextView, I cannot get any moment of MotionEvent.ACTION_MOVE
For example take a look at the code below:
public boolean onTouch(View view, MotionEvent me) {
if (me.getAction() == MotionEvent.ACTION_DOWN) {
Log.e(TAG,"1");
}
if (me.getAction() == MotionEvent.ACTION_UP) {
Log.e(TAG,"2");
} else if (me.getAction() == MotionEvent.ACTION_MOVE) {
Log.e(TAG,"3");
}
return false;
}
if I bind this listener to a Button, I can see "3" in my logs, on the other hand, if I bind this to an ImageView or etc. I cannot see any "3". but "1" and "2" are acting normal for both situation.
So the question is (if I am not mistaken) which items are MotionEvent.ACTION_MOVE sensitive?
Try implementing OnClickListener also..like this..and put onClick empty.. I think it then detects ACTION_MOVE, along with ACTION_UP and ACTION_DOWN..
class MyActivity implements View.OnTouchListerner, View.OnClickListener{
.....
public void onClick(View v) {}
.....
}
Textview doen't hava any MotionEvent ActionMove, http://developer.android.com/reference/android/widget/TextView.html..
Thanks...

OnTouchListener() will only execute once while button is pressed and held down

brown = (Button) findViewById(R.id.brownButton);
brown.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
count++;
Log.d("count", "" + count);
return true;
} else if (event.getAction() == (MotionEvent.ACTION_UP)) {
count--;
Log.d("count", "" + count);
return true;
}
return false;
}
});
When my finger presses and holds the button my count will only increment ONCE. When I let go it will decrement accordingly. Please can someone show me how I can get my code to increment as long as my finger is holding the button down. Thanks.
A touch listener works like this:
It receives a ACTION_DOWN event (the user touches)
It then receives all the following events (if true is returned) and treats all the following events as ACTION_MOVE events
The touch lisetener keeps receiving ACTION_MOVE events until it receives an ACTION_UP or ACTION_CANCEL event.
So ACTION_DOWN is only triggered once, then any number of ACTION_MOVE events, then either a single ACTION_UP or ACTION_CANCEL.
If you want your counter to increment you need to check for ACTION_MOVE events.
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
//do something on DOWN
break;
case MotionEvent.ACTION_MOVE:
//do something on MOVE
break;
case MotionEvent.ACTION_UP:
//do something on UP
break;
}
return true;
}
I also needed to do this, but this question was never adequately answered, even though it is fairly old. However, a good solution can be found here: android repeat action on pressing and holding a button
I am adapting that solution to this problem. I tested it and it works for me.
Button brown = (Button) findViewById(R.id.brownButton);
brown.setOnTouchListener(new View.OnTouchListener() {
private Handler mHandler;
private int count = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (mHandler != null)
return true;
mHandler = new Handler();
mHandler.postDelayed(mAction, 500);
break;
case MotionEvent.ACTION_UP:
if (mHandler == null)
return true;
mHandler.removeCallbacks(mAction);
mHandler = null;
break;
}
return true; // before I had written false
}
Runnable mAction = new Runnable() {
#Override
public void run() {
Log.d("count: ", "" + count);
count++;
mHandler.postDelayed(this, 500);
}
};
});
In the future I will apply this solution to a custom soft keyboard to allow the space and delete keys to continue working when being held down.
Update: Today I finally got around to making the continuous delete key. I thought I had tested my above code before, but today when I was doing it I had to return true from the onTouch method in order to get it to work.

Categories