Mapbox touchlistner 地图

Mapbox touchlistner for map

您好,我正在使用 mapbox 在 android 应用程序中显示地图。我陷入了需要获取用户可见的地图半径的情况。如果用户放大或缩小地图的半径会发生变化。任何人都可以告诉我该怎么做或建议我参考 link 关于这个

我假设半径是指用户当前可见的地图距离?如果是这种情况,您可以获得东西边界之间的绝对距离(以度为单位)。

LatLngBounds latLngBounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
latLngBounds.getLongitudeSpan();

如果这不是您要找的,请告诉我。

要检测地图比例何时更改,您需要向 MapboxMap 添加一个侦听器。这是一个 class 的示例,它扩展 MapView 以在底部添加一个比例尺,该比例尺会随着地图缩放或平移而动态调整大小(平移会改变距离的比例,但不会改变度数。)这是它的样子:

几点:从 MapView 获取 MapboxMap 的唯一方法是异步请求它。 Activity 或托管地图的片段应该这样做。此 class 覆盖 getMapAsync() 以允许它也获得对 MapboxMap 的引用,但托管 Activity 仍然需要调用该方法。

相机变化事件被报告给一个监听器,并且在 MapboxMap 上一次只能设置一个,所以如果主机 activity 有一个监听器,它应该调用 ScaledMapView#onCameraChange() 在该侦听器的类似命名方法中。

MapView 本身必须包含在 FrameLayout 中才能添加比例视图。

显然,您可以简单地将相同的基本代码合并到您的 Activity 或 Fragment 中,并在布局中包含缩放 TextView,而不是以编程方式添加它。

扩展class:

package com.controlj.test;

import android.content.Context;
import android.location.Location;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;

import java.util.Locale;

/**
 * Created by clyde on 2/10/2016.
 * This class extends the Mapbox Mapview to add a scale at the bottom
 */

public class ScaledMapview extends MapView implements MapboxMap.OnCameraChangeListener, OnMapReadyCallback {
    private TextView scaleText;
    private MapboxMap mapboxMap;
    private OnMapReadyCallback callback;
    private ScaleUnit scaleUnit = ScaleUnit.KM;
    private float labelWidth = 0.33f;

    public float getLabelWidth() {
        return labelWidth;
    }

    public void setLabelWidth(float labelWidth) {
        if(labelWidth > 1f)
            labelWidth = 1f;
        else if(labelWidth < 0.1f)
            labelWidth = 0.1f;
        this.labelWidth = labelWidth;
    }

    public ScaleUnit getScaleUnit() {
        return scaleUnit;
    }

    public void setScaleUnit(ScaleUnit scaleUnit) {
        this.scaleUnit = scaleUnit;
    }

    enum ScaleUnit {
        MILE("mile", 1609.344f),
        NM("nm", 1852.0f),
        KM("km", 1000.0f);

        ScaleUnit(String unit, float ratio) {
            this.unit = unit;
            this.ratio = ratio;
        }

        String unit;
        float ratio;
    }

    public ScaledMapview(@NonNull Context context) {
        super(context);
    }

    public ScaledMapview(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public ScaledMapview(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public ScaledMapview(@NonNull Context context, @Nullable MapboxMapOptions options) {
        super(context, options);
    }

    @Override
    public void getMapAsync(OnMapReadyCallback callback) {
        this.callback = callback;
        super.getMapAsync(this);
    }

    /**
     * To ensure this is called when the camera changes, either this ScaledMapview must be passed
     * to mapboxMap.setOnCameraChangeListener() or whatever is listening must also call this method
     * when it is called.
     *
     * @param position The CameraPosition at the end of the last camera change.
     */
    @Override
    public void onCameraChange(CameraPosition position) {
        if (scaleText == null) {
            ViewParent v = getParent();
            if (v instanceof FrameLayout) {
                scaleText = (TextView)inflate(getContext(), R.layout.mapscale, null);
                ((FrameLayout)v).addView(scaleText);
            }
        }
        if (scaleText != null) {
            // compute the horizontal span in metres of the bottom of the map
            LatLngBounds latLngBounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
            float span[] = new float[1];
            Location.distanceBetween(latLngBounds.getLatSouth(), latLngBounds.getLonEast(),
                    latLngBounds.getLatSouth(), latLngBounds.getLonWest(), span);

            float totalWidth = span[0] / scaleUnit.ratio;
            // calculate an initial guess at step size
            float tempStep = totalWidth * labelWidth;

            // get the magnitude of the step size
            float mag = (float)Math.floor(Math.log10(tempStep));
            float magPow = (float)Math.pow(10, mag);

            // calculate most significant digit of the new step size
            float magMsd = (int)(tempStep / magPow + 0.5);

            // promote the MSD to either 1, 2, or 5
            if (magMsd > 5.0f)
                magMsd = 10.0f;
            else if (magMsd > 2.0f)
                magMsd = 5.0f;
            else if (magMsd > 1.0f)
                magMsd = 2.0f;
            float length = magMsd * magPow;
            if (length >= 1f)
                scaleText.setText(String.format(Locale.US, "%.0f %s", length, scaleUnit.unit));
            else
                scaleText.setText(String.format(Locale.US, "%.2f %s", length, scaleUnit.unit));
            // set the total width to the appropriate fraction of the display
            int width = Math.round(getWidth() * length / totalWidth);
            LayoutParams layoutParams =
                    new LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
            layoutParams.bottomMargin = 4;
            scaleText.setLayoutParams(layoutParams);
        }
    }

    @Override
    public void onMapReady(MapboxMap mapboxMap) {
        this.mapboxMap = mapboxMap;
        // if the owner of this view is listening for the map, pass it through. If not, we must
        // listen for camera events ourselves.
        if (callback != null)
            callback.onMapReady(mapboxMap);
        else
            mapboxMap.setOnCameraChangeListener(this);
        onCameraChange(null);
    }
}

Activity:

package com.controlj.test;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.mapbox.mapboxsdk.MapboxAccountManager;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    ScaledMapview mapView;

    @Override
    protected void onStart() {
        Log.d(TAG, "OnStart()");
        super.onStart();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "OnCreate()");
        MapboxAccountManager.start(this, getString(R.string.mapbox_access_token));
        setContentView(R.layout.activity_main);
        mapView = (ScaledMapview)findViewById(R.id.mapview);
        mapView.onCreate(savedInstanceState);
        mapView.getMapAsync(null);
    }
    @Override
    public void onDestroy() {
        Log.d(TAG, "OnDestroy()");
        super.onDestroy();
        mapView.onDestroy();

    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView.onLowMemory();
    }

    @Override
    public void onPause() {
        Log.d(TAG, "OnPause()");
        mapView.onPause();
        super.onPause();
    }

    @Override
    public void onResume() {
        Log.d(TAG, "OnResume()");
        super.onResume();
        mapView.onResume();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        Log.d(TAG, "OnSaveInstanceState()");
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }
}

activity布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.controlj.test.MainActivity">

        <com.controlj.test.ScaledMapview
            android:id="@+id/mapview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            mapbox:access_token="@string/mapbox_access_token"
            mapbox:center_latitude="-31.42166667"
            mapbox:center_longitude="152.75833333"
            mapbox:style_url="@string/mapbox_style"
            mapbox:zoom="4"/>
</FrameLayout>

以及比例小部件本身的布局。图像资源 @drawable/scale 是一个 9 补丁图像文件。

<?xml version="1.0" encoding="utf-8"?>
<TextView
    android:id="@+id/scale_text"

    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center|bottom"
    android:textAlignment="center"
    android:background="@drawable/scale"
    android:paddingBottom="2dp"
    android:layout_marginBottom="6dp"
    android:layout_marginTop="0dp"
    android:paddingTop="0dp"
    android:text="100km"/>