回答

25

這裏是確定拖曳開始和結束拖動事件可能的解決方法:

必須擴展SupportMapFragment或MapFragment。在onCreateView中,您必須將自己的MapView包裝在自定義的FrameLayout中(在下面的示例中,它是「TouchableWrapper」類),您可以在其中攔截觸摸事件並識別是否輕敲地圖。如果您的「onCameraChange」被調用,只需檢查地圖視圖是否被按下(例如下面的例子是變量「mMapIsTouched」)。

示例代碼:

UPDATE 1:在getView

  • 返回原始創建的視圖()
  • 使用dispatchTouchEvent()而不是onInterceptTouchEvent()

定製的FrameLayout:

private class TouchableWrapper extends FrameLayout { 

    @Override 
    public boolean dispatchTouchEvent(MotionEvent ev) { 

     switch (ev.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       mMapIsTouched = true; 
       break; 
      case MotionEvent.ACTION_UP: 
       mMapIsTouched = false; 
       break; 
     } 

     return super.dispatchTouchEvent(ev); 

    } 

} 

在您的自定義MapFragment:

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup parent, 
     Bundle savedInstanceState) { 
    mOriginalContentView = super.onCreateView(inflater, parent, 
      savedInstanceState); 

    mTouchView = new TouchableWrapper(getActivity()); 
    mTouchView.addView(mOriginalContentView); 

    return mTouchView; 
} 

@Override 
public View getView() { 
    return mOriginalContentView; 
} 

在你的相機更改回調方法:

private final OnCameraChangeListener mOnCameraChangeListener = 
     new OnCameraChangeListener() { 

    @Override 
    public void onCameraChange(CameraPosition cameraPosition) { 
     if (!mMapIsTouched) { 
      refreshClustering(false); 
     } 
    } 
}; 
+1

嘿@Alexey Zakharov,請在Google地圖問題跟蹤器中查看主題:http://code.google.com/p/gmaps-api-issues/issues/detail?id=4636&q=apitype%3DAndroid2&sort=修改後的&colspec = ID%20Type%20Status%20Introduced%20Fixed%20Summary%20Stars%20ApiType%20Internal%20Modified – AZ13

+0

的確如此。不確定在確定ACTION_UP事件後,onCameraChanged()將被調用。無論如何,我也希望Google能很快解決這個問題! – AZ13

+0

非常有幫助的答案,謝謝 –

8

我會嘗試一個onCameraChangeListener。每次攝像機移動結束時,都會調用監聽器。聽衆也會給你新的位置。在我的測試中,聽者在拖動過程中經常被調用,也許有更好的解決方案。

+2

我發現這種方法,但正如你所說的那樣,它經常發生。我只需要在用戶停止拖動地圖並放開手指時進行地理編碼。因此,我似乎也需要處理自己。但是新地圖API中沒有onTouch處理程序。 –

+0

@AlexeyZakharov是對的,它經常被觸發導致動畫卡住AZ13的答案是一個非常好的答案。 – TypingPanda

23

使用AZ13的解決方案之上,並跑入在評論中提到的問題後,我創建了以下解決方案,這可以更可靠地解決問題。但是,由於我在onRelease事件之後使用計時器來確定地圖是否仍然具有動畫效果,因此此解決方案中存在一些延遲。

的代碼可以在Github上通過此鏈接找到:https://github.com/MadsFrandsen/MapStateListener

我的解決方案可以從活動以下列方式使用:

new MapStateListener(mMap, mMapFragment, this) { 
    @Override 
    public void onMapTouched() { 
    // Map touched 
    } 

    @Override 
    public void onMapReleased() { 
    // Map released 
    } 

    @Override 
    public void onMapUnsettled() { 
    // Map unsettled 
    } 

    @Override 
    public void onMapSettled() { 
    // Map settled 
    } 
}; 
+3

似乎爲我工作得很好,它是一個很好的增強@ Az13解決方案:) – Javier

+0

@Mads Frandsen,可能會分享你如何將你的庫與標記setOnMarkerClickListener?我嘗試使用你的庫,當按下任何標記時,代碼將始終在MapSettled功能上執行 –

+0

@simeh是的,我認爲任何觸摸都會被視爲不穩定。您可以在將其設置爲未解決之前檢查是否有任何移動 - 這可以避免onMapSettled調用,只需點擊即可。如果到那時您還沒有解決問題,我可能會在本週末或下一週通過我的(舊)代碼。 –

0
@Override 
public boolean onTouchEvent(MotionEvent event, MapView mapView){ 

    if(event.getAction() == MotionEvent.ACTION_MOVE) 
     return true; 

    return false; 
} 
+2

這個問題被標記爲低質量,因爲如果它的長度和內容。你可以添加一個解釋如何解決這個問題,也許引用使用的功能? – Popnoodles

0

我認爲事件的onclick在地圖是:map.setOnMapClick ... 但是事件拖動是:map.onCameraChangeListener因爲我在這兩個函數中調用了log.e,並且它顯示如onClick view和onDrag view。所以只是爲你使用它們。

4

從播放服務地圖開始9.4。0您可以簡單地使用GoogleMap.OnCameraMoveStartedListenerGoogleMap.OnCameraMoveListenerGoogleMap.OnCameraIdleListener

如果出於某種原因想要使用現在已棄用的舊API,則可以使用onCameraChangeListener。但您必須注意以下兩件事:

  1. onCameraChange()可能會在拖動地圖或拖動地圖一次(拖動停止時)時被調用很多次。
  2. 上次調用onCameraChange()時的相機位置可能與最終相機位置略有不同。

下面的代碼需要這兩個問題考慮:

private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1; 
private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2; 
private CameraPosition lastCameraPosition; 
private Handler handler; 
private GoogleMap googleMap; 

public void onMapReady(GoogleMap theGoogleMap) { 
    googleMap = theGoogleMap; 

    handler = new Handler() { 
     public void handleMessage(Message msg) { 
      if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) { 
       lastCameraPosition = googleMap.getCameraPosition(); 
      } else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) { 
       if (lastCameraPosition.equals(googleMap.getCameraPosition())) { 
        Log.d(LOG, "Camera position stable"); 
       } 
      } 
     } 
    }; 

    googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() { 
     @Override 
     public void onCameraChange(CameraPosition cameraPosition) { 
      handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION); 
      handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION); 
      handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300); 
      handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600); 
     } 
    }); 
} 
0

在Xamarin的Android的處理程序內類,基於Tobus答案增強溶液:

public void OnMapReady(GoogleMap googleMap) 
{ 
     _googleMap = googleMap; 

     if (_googleMap != null) 
     { 
      _cameraPositionHandler = new CameraPositionlHandler(_googleMap); 

      _googleMap.CameraChange += OnCameraChanged; 

     } 
} 

void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e) 
{ 
    _cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION); 
    _cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION);     
    _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300); 
    _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600); 

} 

用下面的內部類:

private class CameraPositionlHandler : Handler 
    { 
     private CameraPosition _lastCameraPosition; 
     private GoogleMap _googleMap; 

     public CameraPositionlHandler (GoogleMap googleMap) 
     { 
      _googleMap = googleMap; 
     } 

     public override void HandleMessage(Message msg) 
     { 
      if (_googleMap != null) 
      { 
       if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) { 
        _lastCameraPosition = _googleMap.CameraPosition; 
       } else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) { 
        if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) { 
         Console.WriteLine("Camera position stable"); 
         //do what you want 
        } 
       } 
      } 
     } 
    } 
26

查看新的m aps api。

@Override 
public void onMapReady(GoogleMap map) { 
    mMap = map; 

    mMap.setOnCameraIdleListener(this); 
    mMap.setOnCameraMoveStartedListener(this); 
    mMap.setOnCameraMoveListener(this); 
    mMap.setOnCameraMoveCanceledListener(this); 

    // Show Sydney on the map. 
    mMap.moveCamera(CameraUpdateFactory 
      .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10)); 
} 

@Override 
public void onCameraMoveStarted(int reason) { 

    if (reason == OnCameraMoveStartedListener.REASON_GESTURE) { 
     Toast.makeText(this, "The user gestured on the map.", 
         Toast.LENGTH_SHORT).show(); 
    } else if (reason == OnCameraMoveStartedListener 
          .REASON_API_ANIMATION) { 
     Toast.makeText(this, "The user tapped something on the map.", 
         Toast.LENGTH_SHORT).show(); 
    } else if (reason == OnCameraMoveStartedListener 
          .REASON_DEVELOPER_ANIMATION) { 
     Toast.makeText(this, "The app moved the camera.", 
         Toast.LENGTH_SHORT).show(); 
    } 
} 

@Override 
public void onCameraMove() { 
    Toast.makeText(this, "The camera is moving.", 
        Toast.LENGTH_SHORT).show(); 
} 

@Override 
public void onCameraMoveCanceled() { 
    Toast.makeText(this, "Camera movement canceled.", 
        Toast.LENGTH_SHORT).show(); 
} 

@Override 
public void onCameraIdle() { 
    Toast.makeText(this, "The camera has stopped moving.", 
        Toast.LENGTH_SHORT).show(); 
} 

developers.google.com sample

+0

完美的解決方案! – Blablablabli

1

我有我的動畫標記只要用戶拖動地圖中心。我一直在使用斯塔斯Shakirov答案

MapDragListenerFragment.class

public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback { 

    private Context mContext; 
    private SupportMapFragment supportMapFragment; 
    private Marker centerMarker; 
    private LatLng mapCenterLatLng; 
    private TextView tvLocationName; 
    private Button btnFinalizeDestination; 
    private GoogleMap mGoogleMap; 

    @Nullable 
    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_map_drag_listener, container, false); 
    } 

    @Override 
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 
     mContext = getActivity(); 

     tvLocationName = (TextView) view.findViewById(R.id.tv_location_name); 
    } 

    @Override 
    public void onActivityCreated(@Nullable Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 

     FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();// 
     supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container); 
     if (supportMapFragment == null) { 
      //// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment 
      supportMapFragment = SupportMapFragment.newInstance(); 
      fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit(); 
     } 
     supportMapFragment.getMapAsync(this); 

    } 

    @Override 
    public void onMapReady(GoogleMap googleMap) { 

     if (googleMap != null) { 
      mGoogleMap = googleMap; 

      centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target) 
        .title("Center of Map") 
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green))); 

      mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { 
       @Override 
       public void onCameraIdle() { 
        mapCenterLatLng = mGoogleMap.getCameraPosition().target; 

        animateMarker(centerMarker,mapCenterLatLng,false); 

        Toast.makeText(mContext, "The camera has stopped moving.", 
          Toast.LENGTH_SHORT).show(); 

        String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude); 
        tvLocationName.setText(address); 
       } 
      }); 
      mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() { 
       @Override 
       public void onCameraMoveStarted(int reason) { 
        if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) { 
         ///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + " Long :" + mapCenterLatLng.longitude); 
         Toast.makeText(mContext, "The user gestured on the map.", 
           Toast.LENGTH_SHORT).show(); 
        } else if (reason == GoogleMap.OnCameraMoveStartedListener 
          .REASON_API_ANIMATION) { 
         Toast.makeText(mContext, "The user tapped something on the map.", 
           Toast.LENGTH_SHORT).show(); 
        } else if (reason == GoogleMap.OnCameraMoveStartedListener 
          .REASON_DEVELOPER_ANIMATION) { 
         Toast.makeText(mContext, "The app moved the camera.", 
           Toast.LENGTH_SHORT).show(); 
        } 
       } 
      }); 
      mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { 
       @Override 
       public void onCameraMove() { 
        Toast.makeText(mContext, "The camera is moving.", 
          Toast.LENGTH_SHORT).show(); 
       } 
      }); 
      mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() { 
       @Override 
       public void onCameraMoveCanceled() { 
        Toast.makeText(mContext, "Camera movement canceled.", 
          Toast.LENGTH_SHORT).show(); 
       } 
      }); 

      mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded. 

      if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != 
        PackageManager.PERMISSION_GRANTED && 
        ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != 
          PackageManager.PERMISSION_GRANTED) { 
       return; 
      } 
      mGoogleMap.setMyLocationEnabled(true); 
      mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15)); 

      mGoogleMap.setOnMapLoadedCallback(this); 
      mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { 
       @Override 
       public void onCameraMove() { 

       } 
      }); 
     } 
    } 

    public void animateMarker(final Marker marker, final LatLng toPosition, 
           final boolean hideMarker) { 
     final Handler handler = new Handler(); 
     final long start = SystemClock.uptimeMillis(); 
     Projection proj = mGoogleMap.getProjection(); 
     Point startPoint = proj.toScreenLocation(marker.getPosition()); 
     final LatLng startLatLng = proj.fromScreenLocation(startPoint); 
     final long duration = 500; 
     final Interpolator interpolator = new LinearInterpolator(); 
     handler.post(new Runnable() { 
      @Override 
      public void run() { 
       long elapsed = SystemClock.uptimeMillis() - start; 
       float t = interpolator.getInterpolation((float) elapsed 
         /duration); 
       double lng = t * toPosition.longitude + (1 - t) 
         * startLatLng.longitude; 
       double lat = t * toPosition.latitude + (1 - t) 
         * startLatLng.latitude; 
       marker.setPosition(new LatLng(lat, lng)); 
       if (t < 1.0) { 
        // Post again 16ms later. 
        handler.postDelayed(this, 16); 
       } else { 
        if (hideMarker) { 
         marker.setVisible(false); 
        } else { 
         marker.setVisible(true); 
        } 
       } 
      } 
     }); 
    } 
} 

其中fragment_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <RelativeLayout 
     android:layout_width="match_parent" 
     android:layout_height="0dp" 
     android:layout_weight="1"> 

     <fragment 
      android:id="@+id/map_container" 
      android:name="com.google.android.gms.maps.SupportMapFragment" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" /> 

     <ImageView 
      android:id="@+id/iv_center_overlay" 
      android:layout_width="25dp" 
      android:layout_height="25dp" 
      android:visibility="gone" 
      android:layout_centerInParent="true" 
      android:src="@drawable/start_blue" /> 
    </RelativeLayout> 


    <TextView 
     android:id="@+id/tv_location_name" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:padding="4dp" 
     android:text="Location Name" /> 
</LinearLayout> 

其中 MapDragListenerActivity

實現了它
public class MapDragListenerActivity extends AppCompatActivity { 

    private Context mContext; 
    private static final String TAG = MapDragListenerFragment.class.getSimpleName(); 
    private MapDragListenerFragment mapDragListenerFragment; 

    private Button selectPlaceBtn; 
    public static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1219; 

    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_map_drag_listener); 

     mContext = MapDragListenerActivity.this; 

     mapDragListenerFragment = new MapDragListenerFragment(); 
     getSupportFragmentManager().beginTransaction() 
       .replace(R.id.frame_container,//where frame_container is a FrameLayout 
         mapDragListenerFragment, 
         MapyFragment.class.getSimpleName()).commit(); 


     selectPlaceBtn = (Button) findViewById(R.id.btn_select_place); 

     selectPlaceBtn.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       try { 
        Intent intent = new PlaceAutocomplete.IntentBuilder(
          PlaceAutocomplete.MODE_FULLSCREEN).build(MapDragListenerActivity.this); 
        startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE); 
       } catch (GooglePlayServicesRepairableException e) { 
        e.printStackTrace(); 
       } catch (GooglePlayServicesNotAvailableException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    @Override 
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
     super.onActivityResult(requestCode, resultCode, data); 

     if(requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE){ 
      if (resultCode == RESULT_OK) { 
       Place place = PlaceAutocomplete.getPlace(mContext, data); 
       if(mapDragListenerFragment != null && mapDragListenerFragment.isVisible()) 
        mapDragListenerFragment.updateMarkerAtPosition(
          place.getLatLng() ,place.getName().toString()); 

       Log.i(TAG, "Place:" + place.toString()); 
      } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) { 
       Status status = PlaceAutocomplete.getStatus(mContext, data); 
       Log.i(TAG, status.getStatusMessage()); 
      } else if (requestCode == RESULT_CANCELED) { 

      } 
     } 
    } 
} 

activity_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <Button 
     android:id="@+id/btn_select_place" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:text="Select Place" /> 

    <FrameLayout 
     android:id="@+id/frame_container" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" /> 

</LinearLayout> 
0

On camera idle is what you should use now

googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { 
     @Override 
     public void onCameraIdle() { 
      //Called when camera movement has ended, there are no pending animations and the user has stopped interacting with the map. 
     } 
}); 
0

最簡單的方法是使用setOnCameraIdleListener方法來處理你的地圖片段觸摸監聽你的舉動最終狀態。 請參閱下面的示例:

mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() { 
    @Override 
    public void onCameraMoveStarted(int i) { 
     mapPin.startAnimation(animZoomOut); 
    } 
}); 

mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() { 
    @Override 
    public void onCameraIdle() { 
     mapPin.startAnimation(animZoomIn); 
    } 
}); 
相關問題