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?
Related
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;
}
I'm making a Tic-Tac-Toe game on Android. My game is running well, but I have a problem with it. When user touch on a tile, I update the UI and then call ComputerPlay() method. But the UI only update after ComputerPlay() method is completed. I don't know how, sorry, my English is bad and I don't know how to search the answer.
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (currentTurn == Constants.HUMAN && board.isEmptyCell(r, c)) {
//update the UI
v.setBackgroundResource(R.drawable.cell_touched);
}
return true;
case MotionEvent.ACTION_UP:
if (currentTurn == Constants.HUMAN && board.isEmptyCell(r, c)) {
//update the tile where user touched
v.setBackgroundResource(R.drawable.cell_normal);
board.makeMove(r, c, currentTurn, options.getHumanPiece());
if (board.checkWinner(currentTurn)) {//if user wins
win++;
tvWin.setText(String.format("Win: %d", win));
tvNotice.setText(R.string.winNotice);
} else if (board.isFull()) { //if draw
draw++;
tvDraw.setText(String.format("Draw: %d", draw));
tvNotice.setText(R.string.drawNotice);
} else {
// computer's turn
currentTurn = Constants.COMPUTER;
ComputerPlay();
}
}
return true;
}
return false;
}
In the code below, when user touches on a tile, I update the UI first and then check for game status. If the game is not end, I call method ComputerPlay(). But the problem is: The UI is really updated after ComputerPlay() method is completed (take more time to search the best move for Computer). I want the UI is updated before ComputerPlay() method starts. How can I do this?
If ComputerPlay() is a long-running method, and you want your UI to update before it is done, you should run ComputerPlay() in an other thread.
I know that if you want to check if someone clicked on something, you would do
if(event.getAction() == MotionEvent.ACTION_DOWN)
But I want to check if the screen hasn't been clicked at all.
What is the code I would produce in order to do this?
Also, as a side note, would it be a good idea to have all the classes in an Android app extend the View classes?
Create a boolean variable called istouched and use onTouchLisener on your top most View actually its a Window that's where your Views are, quick sample
getWindow().getDecorView().setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
// i have been touched
istouched = true;
Toast.makeText(getBaseContext(), "you touched me?!! - i will tell my mom", Toast.LENGTH_SHORT).show();
return true;
}
if(event.getAction() == MotionEvent.ACTION_DOWN){
// you can implement this
Toast.makeText(getBaseContext(), "shhh; i am touching", Toast.LENGTH_SHORT).show();
return true;
}
return false;
}
});
so the logic here is if istouched is false your device is not telling her mom, which means it has not being touched..
hope it helps
One way is to add android:onClick="method" to the root layout in your layout xml.
in the method you can change a boolean variable to true (screenClicked = true).
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().
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.