2009-11-05 24 views
23

Làm cách nào để tôi nhấp vào một lần xem bản đồ để dấu vị trí xuất hiện tại điểm đó trên bản đồ?bản đồ android: Cách bấm Long Map?

Tôi đã thử một vài cách nhưng không thành công:

1) Sử dụng setOnLongClickListener trên MapvView mà không bao giờ phát hiện ra longclicks.

2) Ý tưởng khác của tôi là mở rộng MapView để ghi đè dispatchTouchEvent .. Tạo GestureDetector để trả lời cuộc gọi lại dài. Nhưng tôi đã bị kẹt giữa chừng ở đây vì tôi không thể có được một xử lý cho Mapview phân lớp của tôi. tức là

MyMapview mymapview; //MyMapView extends MapView 

//results in a classcast exception 
mymapView = (MyMapView) findViewById(R.id.map); 

3) Chỉ khác cách tôi biết làm thế nào để thử loại này là: Phát hiện một MotionEvent.ACTION_DOWN và viết Runnable trì hoãn đến một handler và phát hiện nhấn và giữ nếu hai sự kiện khác: acton_move hoặc một action_up, có không đã xảy ra.

Ai đó có thể cung cấp suy nghĩ về bất kỳ phương pháp nào trong số này để phát hiện các máy ép dài không?

Trả lời

8

Cách tốt nhất mà tôi biết để làm điều này là sử dụng mã nguồn mở và sử dụng mapview-overlay-manager nghe cử chỉ của nó cung cấp một callback cho

public void onLongPress(MotionEvent e, ManagedOverlay overlay) 
+0

cảm ơn câu trả lời của bạn .. tôi đã sử dụng thư viện bạn đã đề cập .. tôi thích sử dụng nhấn đúp thay vì nhấn. – vamsibm

+1

Tôi đồng ý; báo chí dài là vấn đề bởi vì nó có thể bật lên khi bạn chỉ di chuyển bản đồ. – I82Much

22

Tôi đã tìm thấy một cách dễ dàng hơn. Chỉ cần tạo lớp phủ làm lớp phủ đầu tiên trong danh sách không vẽ bất kỳ thứ gì và sử dụng lớp phủ đó để nhận ra cử chỉ bằng GestureDetector. Sau đó nó sẽ trả về true nếu nó xử lý sự kiện để nó không được truyền bá.

List<Overlay> overlays = mapView.getOverlays(); 
    overlays.clear(); 
    overlays.add(new MapGestureDetectorOverlay(new MyOnGestureListener())); 

Và đây là các lớp:

public class MapGestureDetectorOverlay extends Overlay implements OnGestureListener { 
private GestureDetector gestureDetector; 
private OnGestureListener onGestureListener; 

public MapGestureDetectorOverlay() { 
    gestureDetector = new GestureDetector(this); 
} 

public MapGestureDetectorOverlay(OnGestureListener onGestureListener) { 
    this(); 
    setOnGestureListener(onGestureListener); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event, MapView mapView) { 
    if (gestureDetector.onTouchEvent(event)) { 
    return true; 
    } 
    return false; 
} 

@Override 
public boolean onDown(MotionEvent e) { 
    if (onGestureListener != null) { 
    return onGestureListener.onDown(e); 
    } 
    return false; 
} 

@Override 
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
    float velocityY) { 
    if (onGestureListener != null) { 
    return onGestureListener.onFling(e1, e2, velocityX, velocityY); 
    } 
    return false; 
} 

@Override 
public void onLongPress(MotionEvent e) { 
    if (onGestureListener != null) { 
    onGestureListener.onLongPress(e); 
    } 
} 

@Override 
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, 
    float distanceY) { 
    if (onGestureListener != null) { 
    onGestureListener.onScroll(e1, e2, distanceX, distanceY); 
    } 
    return false; 
} 

@Override 
public void onShowPress(MotionEvent e) { 
    if (onGestureListener != null) { 
    onGestureListener.onShowPress(e); 
    } 
} 

@Override 
public boolean onSingleTapUp(MotionEvent e) { 
    if (onGestureListener != null) { 
    onGestureListener.onSingleTapUp(e); 
    } 
    return false; 
} 

public boolean isLongpressEnabled() { 
    return gestureDetector.isLongpressEnabled(); 
} 

public void setIsLongpressEnabled(boolean isLongpressEnabled) { 
    gestureDetector.setIsLongpressEnabled(isLongpressEnabled); 
} 

public OnGestureListener getOnGestureListener() { 
    return onGestureListener; 
} 

public void setOnGestureListener(OnGestureListener onGestureListener) { 
    this.onGestureListener = onGestureListener; 
} 
} 
+0

cool .. khá thông minh. có lẽ tôi sẽ cố gắng dùng thử đôi khi, bây giờ tôi đã hoàn thành dự án này. :) – vamsibm

+0

cảm ơn u David..rất hữu ích cho tôi cũng – indira

+1

Cảm ơn bạn đã dành thời gian viết tất cả các mã số – coyotte508

2

Ambrose,

tôi sửa đổi bản demo của thư viện mapview-overlay-manager. để mã này chạy với cử chỉ nhấn đúp:

package de.android1.overlaymanager.demo; 

import android.os.Bundle; 
import android.widget.Toast; 
import android.graphics.drawable.Drawable; 
import android.view.MotionEvent; 
import com.google.android.maps.MapActivity; 

import com.google.android.maps.MapView; 
import com.google.android.maps.MapController; 
import com.google.android.maps.GeoPoint; 

import de.android1.overlaymanager.*; 


public class DemoView extends MapActivity { 

    MapView mapView; 
    MapController mapController; 

    OverlayManager overlayManager; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     mapView = (MapView) findViewById(R.id.mapview); 
     mapView.setBuiltInZoomControls(true); 
     mapController = mapView.getController(); 

     overlayManager = new OverlayManager(getApplication(), mapView); 
    } 

    @Override 
    public void onWindowFocusChanged(boolean b) { 

     createOverlayWithListener(); 

    } 


    public void createOverlayWithListener() { 
     //This time we use our own marker 
     final ManagedOverlay managedOverlay = overlayManager.createOverlay("listenerOverlay", getResources().getDrawable(R.drawable.marker)); 
     for (int i = 0; i < 40; i = i + 3) { 
      managedOverlay.createItem(GeoHelper.geopoint[i], "Item" + i); 
     } 
     managedOverlay.setOnOverlayGestureListener(new ManagedOverlayGestureDetector.OnOverlayGestureListener() { 


      public boolean onZoom(ZoomEvent zoom, ManagedOverlay overlay) { 
       return false; 
      } 


      public boolean onDoubleTap(MotionEvent e, ManagedOverlay overlay, GeoPoint point, ManagedOverlayItem item) { 
       Drawable defaultmarker = getResources().getDrawable(R.drawable.marker);  

       ManagedOverlay managedOverlay = overlayManager.createOverlay(defaultmarker); 

       //creating some marker: 
       managedOverlay.createItem(point); 

       //registers the ManagedOverlayer to the MapView 
       overlayManager.populate(); 
       Toast.makeText(getApplicationContext(), "You created a Marker!", Toast.LENGTH_LONG).show(); 

       return true; 
      } 


      public void onLongPress(MotionEvent arg0, ManagedOverlay arg1) { 
       // TODO Auto-generated method stub 

      } 


      public void onLongPressFinished(MotionEvent arg0, 
        ManagedOverlay arg1, GeoPoint arg2, ManagedOverlayItem arg3) { 
       // TODO Auto-generated method stub 

      } 


      public boolean onScrolled(MotionEvent arg0, MotionEvent arg1, 
        float arg2, float arg3, ManagedOverlay arg4) { 
       // TODO Auto-generated method stub 
       return false; 
      } 


      public boolean onSingleTap(MotionEvent arg0, ManagedOverlay arg1, 
        GeoPoint arg2, ManagedOverlayItem arg3) { 
       // TODO Auto-generated method stub 
       return false; 
      }   
     }); 
     overlayManager.populate(); 
    } 


    @Override 
    protected boolean isRouteDisplayed() { 
     return false; 
    } 
} 

Hy vọng điều đó sẽ hữu ích.

3

Thư viện trình quản lý lớp phủ bản đồ này là siêu. Lý do onLongPress được kích hoạt khi 'di chuyển' là do thư viện không tính đến cảm ứng đa điểm. Bạn có thể làm việc này bằng cách từ chối onLongPress nếu có nhiều hơn một con trỏ tham gia như vậy:

public void onLongPress(MotionEvent motionEvent, ManagedOverlay arg1) { 

    if (motionEvent.getPointerCount() > 1) return; 

    ... your logic here ... 
} 
+0

Nhưng phương thức getPointerCount chỉ khả dụng ở cấp API 5. –

4

này làm việc với bạn MapActivity và sẽ cho phép bạn:

  1. Đặt ngưỡng thời gian của riêng bạn cho những gì tạo thành một báo cáo dài trên bản đồ (0,8 giây là tốt cho tôi).
  2. Không diễn giải sự kiện cuộn, chạm nhiều lần hoặc không liên lạc nhiều lần dưới dạng báo chí dài. Nó cũng cho phép bạn thiết lập một sự khoan dung cho ngón tay của một ai đó để bao giờ nên hơi di chuyển trên màn hình khi họ đang giữ một báo dài.

giải pháp này được dựa trên Roger Kristiansen's solution. Tôi đã thêm phát hiện điểm x và y để cuộn không được xem là báo chí dài. Giải pháp này không thanh lịch như Roger bởi vì tôi sử dụng các biến lớp và đặt mã trong MapActivity hiện tại của tôi thay vì mở rộng MapView và tạo ra một người nghe như anh ta đã làm. Nhưng nếu bạn muốn gắn bó với mã của mình nhưng có hỗ trợ không đa cảm ứng tốt hơn, chỉ cần lấy thứ x và y ra khỏi của tôi và thêm nó vào của mình.


biến lớp học được đặt ở phía trên cùng của MapActivity tôi:

//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 

Thêm chức năng này trong MapActivity của bạn:

@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); 
    } 
+1

đây là giải pháp tuyệt vời cho tôi! –

0

Tôi cũng có một ClassCastException khi tôi cố gắng sử dụng MyMapView. Để giải quyết vấn đề này, tôi đã tạo một đối tượng MyMapView thay vì một đối tượng MapView và đã thêm nó vào bố cục theo chương trình, và nó hoạt động rất tốt.

MyMapView mapView = new MyMapView(this, this.getString(R.string.APIMapKey)); 
    mapView.displayZoomControls(false); 
    mapView.setClickable(true); 
    FrameLayout item = (FrameLayout) findViewById(R.id.getlocationmap); 
    item.addView((MapView)mapView); 
0

Nếu bạn đang đi với trì hoãn bài/thông điệp tới một handler (một giải pháp tôi sử dụng bản thân mình), nó có thể hữu ích để kiểm tra xem bản đồ đã di chuyển, tức là nếu mapView.getMapCenter(), mapView.getLatitudeSpan()mapView.getLongitudeSpan() trả lại giống như khi con trỏ xuống.

Các vấn đề liên quan