I am creating a custom UI component where user can upload an image of a map and then user can specify certain locations and Display a pin. First upon image of the map loaded user will be able to pan and zoom to any position. for this I used following example which works like a charm.
TouchImageView
Next part was to add a pin when it is long pressed on the image. For this I used an Absolute Layout over the map image and added an OnTouchListener and Returned false at the end for the touch listener on ImageView to work as well. I implemented the OnTouchListener As below
absoluteLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, final MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
count=-1;// reset count. Thredd will start as 0
released = false;// Touch long press is started
final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
while(!released){//Stop count if touch released
try {
count++;// Count every 200 ms
Thread.sleep(200);
if(count>10){ //if pressed for 200*10= 2 seconds
released=true;
handler.post(new Runnable() {
#Override
public void run() {
addPin((int) event.getX(), (int) event.getY());//Calling the method to add the pin
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
break;
case MotionEvent.ACTION_UP:
released=true;// touch is released
break;
case MotionEvent.ACTION_MOVE:
released=true; // touch is a movement therefore release long press
break;
}
return false;
}
});
But the issue here is With case :"MotionEvent.ACTION_MOVE" it always make the long press released. But without it if user is trying to pan or zoom the imageView it will add a pin.
How can i detect if there is a movement in the touch and ignore when user is zooming or panning the map?
Thanks in advance.
You can specify a minimum amount of movement to be sure if it's an accidental movement or not, like it's explained here
Related
I am about to write a little quiz app. I have 4 Buttons which represent the possibilities of answers. When one button is depressed It should blink red or green to indicate right or wrong. So far no problem.
But the next step should be to slide out the old question and to slide in the new one. This should initiate by a touch of the user anywhere on the screen.
How can I achieve this? Which methods I have to use?
Code:
#Override
public void onClick(View v) {
Button button = (Button)findViewById(v.getId());
if(button.getText().equals(quizWorld.getCurrentQuestion().getRightAnswer())){
//right
}else{
//wrong
}
}
#Override
public boolean onTouchEvent(MotionEvent event){
switch(event.getAction()){
case MotionEvent.ACTION_UP:
//Game Over?
if(quizWorld.swapQuestion()==false){
viewFlipper.setDisplayedChild(1);
}
break;
}
return true;
}
Just for Explanation: In the onClick the Programm compares the text on the button with the saved answer and initiate the blinking (not coded yet). And on the onTouchEvent it changes the question.
And now: onTouchEvent should be only "activated" when the Programm has just finished the checking process. After that the Programm shouldn't react on OnEventTouch.
If you don't need to handle the touch event, just return false onTouchEvent and let the touch pass through.
#Override
public boolean onTouchEvent(MotionEvent event){
if (I don't need this touch)
{
return false;
}
switch(event.getAction()){
case MotionEvent.ACTION_UP:
//Game Over?
if(quizWorld.swapQuestion()==false){
viewFlipper.setDisplayedChild(1);
}
break;
}
return true;
}
for my app i want to determinate how long i touch the screen. I want use the function onTouchEvent, i don't want use some images or some buttons to do it. Some idea? Otherwise, if there isn't a way, with a buttons but not with a image.
You can catch the movement using MotionEvent.ACTION_DOWN to start the timer and stop it when you catch MotionEvent.ACTION_UP.
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_DOWN){
//start timer
} else if(event.getAction()==MotionEvent.ACTION_UP){
//end timer
}
return true;
}
ZouZou's answer is good, but here's another solution, without struggling with timers. If you have a MotionEvent event then you can use getDownTime() and getEventTime() methods. The difference between them will be the duration of the touch.
#Override
public boolean onTouchEvent(MotionEvent event) {
final long time = (event.getEventTime() - event.getDownTime();
return true;
}
In my application I want to add a simple animation to buttons and other views acting as buttons.
To do this I set a custom onTouchListener to all views and call startAnimation on them.
My onTouch method looks like this:
public boolean onTouch(View v, MotionEvent event) {
// Only show animation when enabled.
if (v.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.startAnimation(shrink);
break;
case MotionEvent.ACTION_UP:
v.startAnimation(grow);
break;
}
}
return v.onTouchEvent(event);
}
This works ok as the views are resized to a smaller size while the user presses the button and returns to the original size when the user releases the finger.
However for some reason other buttons that lie near the touched button also get the UP event so they get a small animation flicker as well.
Why is this, and more importantly, how do I prevent this annoying behaviour?
Edit: Just to be clear. The neighbour views are also registered to the same listener instance, but they are not touched by my finger.
The view to wich you have registered listener then should only get notified then also use following approach.
You can explicitly check what is id of View and then only start animation.
public boolean onTouch(View v, MotionEvent event) {
if (v.getId() == R.id.desired_view_id) {
// Only show animation when enabled.
if (v.isEnabled()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.startAnimation(shrink);
break;
case MotionEvent.ACTION_UP:
v.startAnimation(grow);
break;
}
}
}
return v.onTouchEvent(event);
}
The problem was using the same Animation instance on several views. Creating seperate instances for each view fixed the problem.
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.
Alright so i have 4 image views..
How can i control what happens when they are pressed down and up
So say like:
one of the images is press down a textview gets changed to 1 but when they let go of that one the text will change back to 0?
You need to use an OnTouchListener and have it listen for TouchEvents on your Views.
For Example:
MyTouchListener l = new MyTouchListener();
view.setOnTouchListener(l);
Here is an example of what MyTouchListener could look like:
class MyOnTouchListener implements OnTouchListener {
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
// touch down code
break;
case MotionEvent.ACTION_MOVE:
// touch move code
break;
case MotionEvent.ACTION_UP:
// touch up code
break;
}
return true;
}
}