android maps: How to Long Click a Map?

后端 未结 8 1795
遥遥无期
遥遥无期 2020-12-02 12:41

How do I long click on a mapview so that a place marker appears at that point on the map?

I tried a couple ways without success:

1) Using setOnLongCl

相关标签:
8条回答
  • 2020-12-02 13:17

    This works with your MapActivity and will allow you to:

    1. Set your own time threshold for what constitutes a long press on the map (0.8 seconds is good for me).
    2. Not interpret a scroll, multi-touch, or non-multi-touch event as a long press. It also let's you set a tolerance for someone's finger to ever so slightly move on the screen as they are holding down a long press.

    This solution is based on Roger Kristiansen's solution. I added x and y point detection so that scrolling is not seen as a long press. This solution is not as elegant as Roger's because I use class variables and put the code in my existing MapActivity instead of extending MapView and creating a listener like he did. But if you want to stick with his code but have better non-multi-touch support, just take the x and y point stuff out of mine and add it to his.


    Class variables set at the top of my 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
    

    Add this function in your 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);
        }
    
    0 讨论(0)
  • 2020-12-02 13:20

    There's an implementation for handling long press on maps here:

    http://www.kind-kristiansen.no/2011/android-handling-longpresslongclick-on-map-revisited/

    0 讨论(0)
提交回复
热议问题