I am looking for a way for when a user long touches a mapview (lets say for 1000ms) that i can some how do a certain action.
How would i go about judging how long a user long touches a mapsview(or any view).
It would be similar to android google maps app, when you long touch, it brings up a balloon overlay item.
Edit added
mapView.setOnLongClickListener(new View.OnLongClickListener() {
public boolean onLongClick(View v) {
Toast.makeText(mapView.getContext(), "Hello 123", 2000);
return false;
}
});
the above does not work... any ideas why?
Edit added
This is what i am trying at the moment, but it does not seem to work, even if i only press on the phone, it says the event is an action_move,
i am using an inner class in my MapActivity
private long startTime=0;
private long endTime=0;
class MapOverlay extends Overlay {
#Override
public boolean onTouchEvent(MotionEvent ev, MapView mapView) {
if(ev.getAction() == MotionEvent.ACTION_DOWN){
//record the start time
startTime = ev.getEventTime();
Log.d("LC", "IN DOWN");
}else if(ev.getAction() == MotionEvent.ACTION_UP){
//record the end time
endTime = ev.getEventTime();
Log.d("LC", "IN UP");
}else if(ev.getAction() == MotionEvent.ACTION_MOVE){
Log.d("LC", "IN move");
endTime=0;
}
//verify
if(endTime - startTime > 1000){
//we have a 1000ms duration touch
//propagate your own event
Log.d("LC", "time touched greater than 1000ms");
Toast.makeText(getBaseContext(), "Hello 123", Toast.LENGTH_SHORT).show();
startTime=0;
endTime=0;
return true; //notify that you handled this event (do not propagate)
}
return false;//propogate to enable drag
}
}
and here is my error log that does not make any sense to me
06-29 14:29:55.509: DEBUG/LC(7693): IN move
06-29 14:29:56.149: DEBUG/LC(7693): IN UP
06-29 14:29:56.149: DEBUG/LC(7693): 6346707 6349261
06-29 14:29:56.149: DEBUG/LC(7693): time touched greater than 1000ms
the end time should be set to zero...but it is not...any idea why?
This is how do you normally create an onLongClickListener. Try this:
mapView.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View arg0) {
Toast.makeText(mapView.getContext(), "Hello 123", 2000);
return false;
}
});
Reference to your edit:
This might be the way to get what you want.
private final Handler handler = new Handler();
private final Runnable runnable = new Runnable() {
public void run() {
checkGlobalVariable();
}
};
// Other init stuff etc...
#Override
public void onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN) {
// Execute your Runnable after 1000 milliseconds = 1 second.
handler.postDelayed(runnable, 1000);
mBooleanIsPressed = true;
}
if(event.getAction() == MotionEvent.ACTION_UP) {
if(mBooleanIsPressed) {
mBooleanIsPressed = false;
handler.removeCallbacks(runnable);
}
}
}
And now you can check with checkGlobalVariable function:
if(mBooleanIsPressed == true)
This is how you can handle this case. Good luck.
Your are probably looking for a normal long click?
You will have to set your view to be long clickable by adding android:longClickable to your views xml, or by calling setLongClickable(true).
Then you can add an OnLongClickListener to the view.
I dont know of a way to determine exactly how long the long click is. But the default long click is the same as the google maps long click that you mentioned.
OnLongClickListener
You can set up a longClickListener and a touchListener. Add a boolean class data member variable longClicked and set it to false initially. This is how you can set the longClickListener.
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
longClicked = true;
return false;
}
});
For touchListener
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(longClicked){
//Do whatever you want here!!
longClicked = false;
}
return false;
}
});
It will give you the same effect as google maps long click. Hope it helps.
use System.currentTimeMillis() instead of ev.getEventTime();
When MotionEvent.ACTION_UP, endTime will be set to ev.getEventTime(), this make setting endTime to zero when MotionEvent.ACTION_MOVE be not affect.
Instead of setting endTime to zero, you should set startTime to ev.getEventTime()
This is how I use long and short touches
View.setOnTouchListener(new View.OnTouchListener() {
double firsttouch=0;
boolean isup=false;
int millistotouch=1000;
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction()==MotionEvent.ACTION_DOWN) {
firsttouch = (double) System.currentTimeMillis();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (!isup) {
//
// Do your long click work
//
}
else
{
firsttouch=0;
isup=false;
}
}
}
}, millistotouch);
return true;
}
if (motionEvent.getAction()==MotionEvent.ACTION_UP) {
if (((double) System.currentTimeMillis()-firsttouch)<millistotouch)
{
isup=true;
//
// Do your short click work
//
}
}
return false;
}
});
Related
in this function,I want to achieve “if is long press,return flag=true,else open tile”.`
public boolean onTouchEvent(MotionEvent event) {
int x=(int)event.getX();
int y=(int)event.getY();
long DownTime = event.getDownTime();
long UpTime = event.getEventTime();
long longPresstouch = UpTime - DownTime;
int idxX=(x-mine.x)/mine.tileWidth;
int idxY=(y-mine.y)/mine.tileWidth;
if(longPresstouch > longTouchTime)
{
if(x>=mine.x&&y>=mine.y&&x<=(mine.mapWidth+mine.x)&&y<=(mine.y+mine.mapHeight)) {
mine.setflag(new Mine.Point(idxX, idxY), true);
invalidate();
}
}
else if(event.getAction()==MotionEvent.ACTION_DOWN){
if(x>=mine.x&&y>=mine.y&&x<=(mine.mapWidth+mine.x)&&y<=(mine.y+mine.mapHeight)) //in tile or out tile
{
mine.open(new Mine.Point(idxX,idxY),isFirst);
isFirst=false;
if(mine.tile[idxY][idxX].value==-1)
{
mine.isDrawAllMine=true;
new AlertDialog.Builder(context)
.setCancelable(false)
.setMessage("GameOver,你踩到地雷啦!")
.setPositiveButton("再来一局", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
mine.init();
isFalse=true;
isFirst=true;
invalidate();
}
})
.setNegativeButton("退出游戏", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0);
}
})
.create()
.show();
}
if(isFalse)
{
isFalse=false;
invalidate();
return true;
}
logic();
invalidate();
}
}
return true;
}
`
but It is not working when I long press the tile. It is executing “open tile”.
How to correct the function? I am a beginner. Maybe this is a very simple question,but this has already perplexed me for a long time.
Every Android components that extend android.view.View will have these 2 methods.
View.setOnClickListener() If you do a click.
View.setOnLongClickListener() If you do long click. Make sure it's View.isLongClickable() returns true, or set it by calling View.setLongClickable(true).
Because you're reacting to the down and showing the dialog. Since you're reacting to the down event immediately, you never wait to see if its a long press. This is why touch events in android generally happen on the up event- so you can figure out if the touch is going to be a press, long press, gesture, etc.
Also, as another poster said, click and long clock are built in events. No reason to write an onTouchEvent unless you want to capture more complex behavior.
Calculate the time difference between ACTION_DOWN and ACTION_UP. If time difference is greater than 1000 ms return true else open the tile.
I'm trying to set my own long click listener on Unlock button. Whenever I press the Unlock button it summarize duration and I can unlock permanently clicking.
Unlock.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(final View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Unlock.setText("Press to unlock");
isLongPress = true;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (isLongPress) {
Unlock();
}
}
}, longClickDuration); //amount of time of long click
} else if (event.getAction() == MotionEvent.ACTION_UP) {
Unlock.setText("Unlock");
isLongPress = false;
}
return true;
}
});
}catch (Exception e) {
// TODO: handle exception
}
}
If you want to just handle long clicks consider using the following code:
Unlock.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
your code
}
});
But if the Unlock(); should be invoked after a certain (customizable) amount of time, you should measure this time in MotionEvent.ACTION_UP handler. As #Attaullah Khan said, use SystemClock.elapsedRealtime() system timer to correctly count number of milliseconds at two moments (when button was pressed and released) and if the time is greater than longClickDuration then invoke Unlock
The handler.postDelayed that you call in MotionEvent.ACTION_DOWN handler just invokes a check of pressed state after longClickDuration interval and if your button gets suddenly pressed at that moment, the verification passes that is not correct
I have survey about this subject in a day.
What I mean is how to show toast when tapping the Videoview for a while.
Below is what I've found,
Android: Why can't I give an onClickListener to a VideoView?
detect double tap (Double click) or long click in a videoview
But these really can't solve my problem.I really don't know what has happend?
And is there any function can fire up long pressing event in the video view?
here's my code
these two event really can't work.
mVideoView.setOnLongClickListener(new OnLongClickListener() {
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
final int arg2, long arg3) {
Log.e("devon","onitemlongclick");
return true;
}
#Override
public boolean onLongClick(View v) {
Log.e("devon","onLongClick");
return true;
}
});
need help !!!thanks!
add OnLongClickListener in your setupViewComponent call
try using onTouch
try attaching the OnLongClickListener to the videoview's surface
try wrapping the videoview with a transparent imageview/something that grabs focus, and use that as your 'touching pad'
post logcat.
This is a sample example on how to create your own TouchListsners for managing Click and LongClick on VideoView. In this example I pass to the listeners the idex of the data clicked and the index of the view (in behind I have several VideoView in arrays maps to data list, like in an Adapter)
/**
* Simple OnTouchListenerIndexed with Indexes for VideoView ClickListeners
* You have to handle longClick and click by yourself
*/
private abstract class OnTouchListenerIndexed implements OnTouchListener {
private static final int LONG_CLICK_DURATION=600;//in millis
int dataIndex = INDEX_NOT_DEFINED;
int imageViewIndex = INDEX_NOT_DEFINED;
long timeActionDown;
AtomicBoolean stillNotConsumed=new AtomicBoolean(true);
AtomicBoolean actionDone=new AtomicBoolean(false);
public OnTouchListenerIndexed(int dataIndex, int imageViewIndex) {
this.dataIndex = dataIndex;
this.imageViewIndex = imageViewIndex;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
timeActionDown=System.currentTimeMillis();
stillNotConsumed.set(true);
actionDone.set(false);
//launch LongClick in 1s
v.postDelayed(new Runnable() {
#Override
public void run() {
if(stillNotConsumed.get()){
stillNotConsumed.set(false);
actionDone.set(true);
onLongTouch(dataIndex, imageViewIndex);
}
}
},LONG_CLICK_DURATION);
//consumed
return true;
}else if(event.getAction() == MotionEvent.ACTION_UP){
long timeActionUp=System.currentTimeMillis();
stillNotConsumed.set(false);
if(actionDone.get()){
//do nothing
return true;//you have consumed it
}else {
actionDone.set(true);
//Check Click or LongClick
if (timeActionUp - timeActionDown > LONG_CLICK_DURATION) {
//une seconde plus tard
return onLongTouch(dataIndex, imageViewIndex);
} else {
return onTouch(dataIndex, imageViewIndex);
}
}
}else{
//don't consume it
return false;
}
}
public abstract boolean onTouch(int dataIndex, int imageViewIndex);
public abstract boolean onLongTouch(int dataIndex, int imageViewIndex);
}
I want to lower (or upper) my media volume in my application when an "OnLongClickEvent" is detected.
Here my sources :
buttongauche.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
playSound(R.raw.volumevoixdiminue);
audio.adjustStreamVolume(AudioManager.STREAM_MUSIC,AudioManager.ADJUST_LOWER,AudioManager.FLAG_SHOW_UI);
return true;
}
});
Actually, it's work : when I do a longClick on my "buttongauche", the volume is decreased by 1.
Now I would like to know how could I do if I want to lower the sound continuously (for example, decrease sound by 1 every 2 seconde when the button is down).
My button "buttongauche" has already an "onClickEvent", who do other things (change the index of a menu).
Thanks
Declare field boolean touching = false; that says whether or not you are touching the button and use OnTouchListener to change it. When you start touching also start volumeThread that lowers the volume every 1 second, and dies when you stop touching.
buttongauche.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touching = true;
Thread volumeThread = new Thread() {
public void run() {
while (touching) {
audio.adjustStreamVolume(
AudioManager.STREAM_MUSIC,
AudioManager.ADJUST_LOWER,
AudioManager.FLAG_SHOW_UI);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
volumeThread.start();
break;
case MotionEvent.ACTION_UP:
touching = false;
break;
}
return false;
}
});
I just registered an OnLongClickListener on my my MapView on an Android app I'm currently writing. For some reason however the onLongClick event doesn't fire.
Here's what I've written so far:
public class FriendMapActivity extends MapActivity implements OnLongClickListener {
private static final int CENTER_MAP = Menu.FIRST;
private MapView mapView;
private MapController mapController;
//...
private boolean doCenterMap = true;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.friendmapview);
this.mapView = (MapView) findViewById(R.id.map_view);
this.mapController = mapView.getController();
mapView.setBuiltInZoomControls(true);
mapView.displayZoomControls(true);
mapView.setLongClickable(true);
mapView.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
//NEVER FIRES!!
return false;
}
});
//...
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_3:
mapController.zoomIn();
break;
case KeyEvent.KEYCODE_1:
mapController.zoomOut();
break;
}
return super.onKeyDown(keyCode, event);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int actionType = ev.getAction();
switch (actionType) {
case MotionEvent.ACTION_MOVE:
doCenterMap = false;
break;
}
return super.dispatchTouchEvent(ev);
}
...
}
May overlays which I'm adding cause the problem?? Any suggestions?
I ran into the same problem and there is a simple solution to your problem actually; it's because you're using the wrong type of listener.
You should use the OnMapLongClickListener() object from the OnMapLongClickListener interface.
Hopefully everything should work properly :)
Please tell me if it works.
I just ran into this problem. I tried the solution above, but it doesn't quite work 100% in that we want the long press action to fire, even if the user is still holding a finger down.
This is how I implemented a solution, using a handler and a delayed task -
As a side note, I used a similar type implementation, but in reverse, to hide/show zoom controls on touch/etc..
private Handler mHandler = new Handler();
private final Runnable mTask = new Runnable() {
#Override
public void run() {
// your code here
}
};
#Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
// record the start time, start the timer
mEventStartTime = ev.getEventTime();
mHandler.postDelayed(mTask, LONG_PRESS_TIME);
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
// record the end time, dont show if not long enough
mEventEndTime = ev.getEventTime();
if (mEventEndTime - mEventStartTime < LONG_PRESS_TIME) {
mHandler.removeCallbacks(mTask);
}
} else {
// moving, panning, etc .. up to you whether you want to
// count this as a long press - reset timing to start from now
mEventStartTime = ev.getEventTime();
mHandler.removeCallbacks(mTask);
mHandler.postDelayed(mTask, LONG_PRESS_TIME);
}
return super.onTouchEvent(ev);
}
In the mean time I found the "solution" (or workaround, call it as you like) by myself. The way I worked through this issue is by using a GestureDetector and forwarding all touch events to that object by implementing an according OnGestureListener interface.
I've posted some code on my blog if anyone is interested:
http://juristr.com/blog/2009/12/mapview-doesnt-fire-onlongclick-event/
Don't ask me why this didn't work by hooking up the OnLongClickListener directly on the MapView. If someone has an explanation let me know :)
UPDATE:
My previously suggested solution using a GestureDetector posed some drawbacks. So I updated the blog post on my site.
In WebView framework code performLongClick() is used to handle long press event, this is how Android copy Text Feature is implemented in Browser, that is why onLongClick is not been fired.