答案 0 :(得分:6)
我必须为我的一个项目实现可拖动标记。我找到的唯一解决方案是扩展现有的Marker类,同时检查拖动事件并相应地更新标记位置。
package com.example.map;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.mapbox.mapboxsdk.api.ILatLng;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.overlay.Marker;
import com.mapbox.mapboxsdk.views.MapView;
import com.mapbox.mapboxsdk.views.util.Projection;
public class DraggableMarker extends Marker {
private static final String TAG = "map.DraggableMarker";
private boolean mIsDragged;
private static final RectF mTempRect = new RectF();
private static final PointF mTempPoint = new PointF();
private float mDx, mDy;
public DraggableMarker(String title, String description, LatLng latLng) {
super(title, description, latLng);
mIsDragged = false;
}
public DraggableMarker(MapView mv, String aTitle, String aDescription, LatLng aLatLng) {
super(mv, aTitle, aDescription, aLatLng);
mIsDragged = false;
}
public boolean drag(View v, MotionEvent event) {
final int action = event.getActionMasked();
if(action == MotionEvent.ACTION_DOWN) {
Projection pj = ((MapView)v).getProjection();
RectF bound = getDrawingBounds(pj, mTempRect);
if(bound.contains(event.getX(), event.getY())) {
mIsDragged = true;
PointF p = getPositionOnScreen(pj, mTempPoint);
mDx = p.x - event.getX();
mDy = p.y - event.getY();
}
}
if(mIsDragged) {
if((action == MotionEvent.ACTION_CANCEL) ||
(action == MotionEvent.ACTION_UP)) {
mIsDragged = false;
} else {
Projection pj = ((MapView)v).getProjection();
ILatLng pos = pj.fromPixels(event.getX() + mDx, event.getY() + mDy);
setPoint(new LatLng(pos.getLatitude(), pos.getLongitude()));
}
}
return mIsDragged;
}
}
稍后您需要在MapView上的触摸事件上添加侦听器,并检查您的标记(或标记集合中的许多标记之一)是否受事件影响。
mMarker = new DraggableMarker(mMapView, "", "", aCenter);
mMarker.setIcon(new Icon(getActivity().getApplicationContext(), Icon.Size.SMALL, "marker-stroked", "FF0000"));
mMapView.addMarker(mMarker);
mMapView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return mMarker.drag(v, event);
}
});
答案 1 :(得分:1)
我最近一直在使用mapbox android SDK,在那里遇到了使用标记获取位置的情况。因此,我自己创建了一个屏幕,屏幕中间带有标记(使用图像视图)。在每个摄像机空闲的侦听器上,您都可以获取屏幕中心的位置。
/**
* Method to create the location picker icon at the center of screen
*/
private void createLocationPickerMarker() {
ivLocationPicker = new ImageView(this); //Here image view is dynamically created
ivLocationPicker.setImageResource(R.drawable.ic_location_picker); //reference to the drawable image
// Statically Set drop pin in center of screen
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER); //image parameters are sent and set at the center
float density = getResources().getDisplayMetrics().density; //get screen density
params.bottomMargin = (int) (12 * density); //inorder to place bottom tip at the center bottom margin added - here 12 is multiplied with the screen density and added as bottom margin as this will be mostly at the centre (based on average value of all density location_picker image height)
ivLocationPicker.setLayoutParams(params); //parameters are set to the image
mapView.addView(ivLocationPicker); //image is added to the map
}
/**
* Method to pick location from marker
*/
private LatLng getLatLngFromMarker() {
return mapboxMap.getProjection().fromScreenLocation(new PointF(ivLocationPicker.getLeft() + (ivLocationPicker.getWidth() / 2), ivLocationPicker.getBottom()));
}
@Override
public void onMapReady(MapboxMap mapboxMap) {
pickedLatLng = getLatLngFromMarker(); // used to pick lat lng while coming to screen
mapboxMap.addOnCameraIdleListener(() -> { //listener for on camera idle change
pickedLatLng = getLatLngFromMarker();
});
}
答案 2 :(得分:1)
您可以为Mapbox使用注释插件。 一种实现是在此仓库https://github.com/everestkid/editablepolygon
中答案 3 :(得分:0)
基本上,我使用setOnTouchListener()
来获取mapview
中的所有触摸位置。然后我将它们转换为坐标。之后,我选择了标记,最后使用setPosition()
进行设置。
YourMapView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getActionMasked();
if(action == MotionEvent.ACTION_DOWN) {
LatLng new_position = YourmapboxMap.getProjection().fromScreenLocation(new PointF(event.getX(),event.getY()));
YourmapboxMap.getMarkers().get(0).setPosition(new_position);
}
return false;
}
});
答案 4 :(得分:0)
创建一个新活动并将以下代码粘贴到您的 java 文件中:
SymbolListenerActivity.java
import android.os.Bundle;
import android.widget.Toast;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.plugins.annotation.OnSymbolClickListener;
import com.mapbox.mapboxsdk.plugins.annotation.OnSymbolDragListener;
import com.mapbox.mapboxsdk.plugins.annotation.OnSymbolLongClickListener;
import com.mapbox.mapboxsdk.plugins.annotation.Symbol;
import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager;
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
/**
* Change symbol icon by pressing on icon
*/
public class SymbolListenerActivity extends AppCompatActivity implements
OnMapReadyCallback {
private MapView mapView;
private static final String MAKI_ICON_CAFE = "cafe-15";
private static final String MAKI_ICON_HARBOR = "harbor-15";
private static final String MAKI_ICON_AIRPORT = "airport-15";
private SymbolManager symbolManager;
private Symbol symbol;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview.
Mapbox.getInstance(this, getString(R.string.mapbox_access_token));//your mapbox access token
// This contains the MapView in XML and needs to be called after the access token is configured.
setContentView(R.layout.activity_annotation_plugin_symbol_listener);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.DARK, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// Set up a SymbolManager instance
symbolManager = new SymbolManager(mapView, mapboxMap, style);
symbolManager.setIconAllowOverlap(true);
symbolManager.setTextAllowOverlap(true);
// Add symbol at specified lat/lon
symbol = symbolManager.create(new SymbolOptions()
.withLatLng(new LatLng(60.169091, 24.939876))
.withIconImage(MAKI_ICON_HARBOR)
.withIconSize(2.0f)
.withTextAnchor("Person First")
.withTextSize(23f)
.withDraggable(true));
// Add click listener and change the symbol to a cafe icon on click
symbolManager.addClickListener(new OnSymbolClickListener() {
@Override
public void onAnnotationClick(Symbol symbol) {
Toast.makeText(SymbolListenerActivity.this,
getString(R.string.clicked_symbol_toast), Toast.LENGTH_SHORT).show();
symbol.setIconImage(MAKI_ICON_CAFE);
symbolManager.update(symbol);
}
});
// Add long click listener and change the symbol to an airport icon on long click
symbolManager.addLongClickListener((new OnSymbolLongClickListener() {
@Override
public void onAnnotationLongClick(Symbol symbol) {
Toast.makeText(SymbolListenerActivity.this,
getString(R.string.long_clicked_symbol_toast), Toast.LENGTH_SHORT).show();
symbol.setIconImage(MAKI_ICON_AIRPORT);
symbolManager.update(symbol);
}
}));
symbolManager.addDragListener(new OnSymbolDragListener() {
@Override
// Left empty on purpose
public void onAnnotationDragStarted(Symbol annotation) {
}
@Override
// Left empty on purpose
public void onAnnotationDrag(Symbol symbol) {
}
@Override
// Left empty on purpose
public void onAnnotationDragFinished(Symbol annotation) {
}
});
Toast.makeText(SymbolListenerActivity.this,
getString(R.string.symbol_listener_instruction_toast), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
活动的 XML 是:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="60.169091"
mapbox:mapbox_cameraTargetLng="24.939876"
mapbox:mapbox_cameraZoom="12" />
</FrameLayout>
权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
我为此使用的依赖
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.6.1'
implementation 'com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.42.6'
implementation 'com.mapbox.mapboxsdk:mapbox-android-navigation:0.42.6'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-places-v9:0.12.0'
在项目级别“build.gradle”文件中
allprojects {
repositories {
google()
jcenter()
maven { url 'https://mapbox.bintray.com/mapbox' }
maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven'
authentication {
basic(BasicAuthentication)
}
credentials {
// Do not change the username below.
// This should always be `mapbox` (not your username).
username = 'mapbox'
password = "YourMapBoxAccessToken
}
}
}
}
答案 5 :(得分:-4)
你有没有探索过Leaflet?他们支持Android,IOS和所有标准移动平台。据我所知,甚至Mapbox SDK都是基于Leaflet构建的。
以下是您可以参考的链接:http://leafletjs.com/examples/mobile.html