繁体   English   中英

Mapbox Android SDK - 可拖动标记

[英]Mapbox Android SDK - Draggable marker

如何在Mapbox Android SDK 中使标记可拖动? 这甚至可能吗?

如果没有,还有哪些其他免费的开放地图引擎支持此功能?

谢谢!

我必须为我的一个项目实现可拖动标记。 我发现的唯一解决方案是使用方法检查拖动事件并相应地更新标记位置来扩展现有的 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);
    }
});

我最近一直在使用 mapbox android SDK,在那里我遇到了使用标记拾取位置的情况。 所以我在 center 创建了一个带有标记(使用图像视图)的屏幕。 在每个相机空闲侦听器上,您都可以获得屏幕中心的位置。

    /**
     * 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();
        });
    }

您可以使用 Mapbox 的注释插件。 实现之一是在这个 repo https://github.com/everestkid/editablepolygon

基本上我使用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;
        }
    });

创建一个新活动并将以下代码粘贴到您的 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
            }
        }
    }
}

你探索过传单吗? 它们确实支持 Android、IOS 和所有标准移动平台。 据我所知,甚至 Mapbox SDK 也是基于 Leaflet 构建的。

这是您可以参考的链接: http : //leafletjs.com/examples/mobile.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM