これは MapActivity で機能し、次のことが可能になります。
- マップ上での長押しを構成する時間のしきい値を独自に設定します (0.8 秒が適切です)。
- スクロール、マルチタッチ、または非マルチタッチ イベントを長押しとして解釈しません。また、誰かが長押ししているときに指が画面上をわずかに動く許容範囲を設定することもできます。
このソリューションは、 Roger Kristiansen のソリューションに基づいています。スクロールが長押しに見えないように、x と y の点検出を追加しました。このソリューションは、Roger のように MapView を拡張してリスナーを作成するのではなく、クラス変数を使用して既存の MapActivity にコードを配置するため、Roger ほどエレガントではありません。しかし、彼のコードに固執したいが、マルチタッチ以外のサポートを改善したい場合は、私のものから x と y ポイントのものを取り出して、彼のものに追加してください。
私の MapActivity の上部に設定されたクラス変数:
//variable for determining long press and then automatically adding a pin to the map
private int minMillisecondThresholdForLongClick = 800;
private long startTimeForLongClick = 0;
private float xScreenCoordinateForLongClick;
private float yScreenCoordinateForLongClick;
private float xtolerance=10;//x pixels that your finger can be off but still constitute a long press
private float ytolerance=10;//y pixels that your finger can be off but still constitute a long press
private float xlow; //actual screen coordinate when you subtract the tolerance
private float xhigh; //actual screen coordinate when you add the tolerance
private float ylow; //actual screen coordinate when you subtract the tolerance
private float yhigh; //actual screen coordinate when you add the tolerance
この関数を MapActivity に追加します。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
/* We want to capture the place the user long pressed on the map and add a marker (pin) on the map at that lat/long.
* This solution:
* 1. Allows you to set the time threshold for what constitutes a long press
* 2. Doesn't get fooled by scrolling, multi-touch, or non-multi-touch events
* Thank you Roger Kind Kristiansen for the main idea
*/
//get the action from the MotionEvent: down, move, or up
int actionType = ev.getAction();
if (actionType == MotionEvent.ACTION_DOWN) {
//user pressed the button down so let's initialize the main variables that we care about:
// later on when the "Action Up" event fires, the "DownTime" should match the "startTimeForLongClick" that we set here
// the coordinate on the screen should not change much during the long press
startTimeForLongClick=ev.getEventTime();
xScreenCoordinateForLongClick=ev.getX();
yScreenCoordinateForLongClick=ev.getY();
} else if (actionType == MotionEvent.ACTION_MOVE) {
//For non-long press actions, the move action can happen a lot between ACTION_DOWN and ACTION_UP
if (ev.getPointerCount()>1) {
//easiest way to detect a multi-touch even is if the pointer count is greater than 1
//next thing to look at is if the x and y coordinates of the person's finger change.
startTimeForLongClick=0; //instead of a timer, just reset this class variable and in our ACTION_UP event, the DownTime value will not match and so we can reset.
} else {
//I know that I am getting to the same action as above, startTimeForLongClick=0, but I want the processor
//to quickly skip over this step if it detects the pointer count > 1 above
float xmove = ev.getX(); //where is their finger now?
float ymove = ev.getY();
//these next four values allow you set a tiny box around their finger in case
//they don't perfectly keep their finger still on a long click.
xlow = xScreenCoordinateForLongClick - xtolerance;
xhigh= xScreenCoordinateForLongClick + xtolerance;
ylow = yScreenCoordinateForLongClick - ytolerance;
yhigh= yScreenCoordinateForLongClick + ytolerance;
if ((xmove<xlow || xmove> xhigh) || (ymove<ylow || ymove> yhigh)){
//out of the range of an acceptable long press, reset the whole process
startTimeForLongClick=0;
}
}
} else if (actionType == MotionEvent.ACTION_UP) {
//determine if this was a long click:
long eventTime = ev.getEventTime();
long downTime = ev.getDownTime(); //this value will match the startTimeForLongClick variable as long as we didn't reset the startTimeForLongClick variable because we detected nonsense that invalidated a long press in the ACTION_MOVE block
//make sure the start time for the original "down event" is the same as this event's "downTime"
if (startTimeForLongClick==downTime){
//see if the event time minus the start time is within the threshold
if ((eventTime-startTimeForLongClick)>minMillisecondThresholdForLongClick){
//make sure we are at the same spot where we started the long click
float xup = ev.getX();
float yup = ev.getY();
//I don't want the overhead of a function call:
xlow = xScreenCoordinateForLongClick - xtolerance;
xhigh= xScreenCoordinateForLongClick + xtolerance;
ylow = yScreenCoordinateForLongClick - ytolerance;
yhigh= yScreenCoordinateForLongClick + ytolerance;
if ((xup>xlow && xup<xhigh) && (yup>ylow && yup<yhigh)){
//**** safe to process your code for an actual long press ****
//comment out these next rows after you confirm in logcat that the long press works
long totaltime=eventTime-startTimeForLongClick;
String strtotaltime=Long.toString(totaltime);
Log.d("long press detected: ", strtotaltime);
/*
//Now get the latitude/longitude of where you clicked. Replace all the code below if you already know how to translate a screen coordinate to lat/long. I know it works though.
//*****************
//I have my map under a tab so I have to account for the tab height and the notification bar at the top of the phone.
// Maybe there are other ways so just ignore this if you already know how to get the lat/long of the pixels that were pressed.
int TabHeightAdjustmentPixels=tabHost.getTabWidget().getChildAt(0).getLayoutParams().height;
int EntireTabViewHeight = tabHost.getHeight();
Display display = getWindowManager().getDefaultDisplay();
int EntireScreenHeight = display.getHeight();
int NotificationBarHeight=EntireScreenHeight-EntireTabViewHeight;
//the projection is mapping pixels to where you touch on the screen.
Projection proj = mapView.getProjection();
GeoPoint loc = proj.fromPixels((int)(ev.getX(ev.getPointerCount()-1)), (int)(ev.getY(ev.getPointerCount()-1)-TabHeightAdjustmentPixels-NotificationBarHeight));
int longitude=loc.getLongitudeE6();
int latitude=loc.getLatitudeE6();
//*****************
//**** here's where you add code to:
// put a marker on the map, save the point to your SQLite database, etc
*/
}
}
}
}
return super.dispatchTouchEvent(ev);
}