在GoogleMap中旋转两层标记图标 [英] Rotate a two layer marker icon in GoogleMap

查看:27
本文介绍了在GoogleMap中旋转两层标记图标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我向地图添加了一组标记,如下所示:

private fun addMarker(googleMap: GoogleMap, location: Location) {
    val options = MarkerOptions()
    options.position(LatLng(location.latitude, location.longitude))
    options.rotation(location.bearing)
    options.anchor(0.5f, 0.5f)
    options.flat(true)

    val drawable = ContextCompat.getDrawable(context, R.drawable.background_vehicle) as LayerDrawable
    val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, canvas.width, canvas.height)
    drawable.draw(canvas)

    options.icon(BitmapDescriptorFactory.fromBitmap(bitmap))
    googleMap.addMarker(options)
}

这是我的抽屉:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/icon_vehicle_marker" />
    <item android:id="@+id/vehicle_image" android:bottom="5dp" 
          android:drawable="@drawable/icon_car" android:left="5dp" 
          android:right="5dp" android:top="10dp" />

</layer-list>

结果如下:

我的问题是,将图标平整并设置旋转,会使可抽屉内的汽车图标旋转到。我只想让第一层旋转。理想情况下,我只希望第一层(蓝色箭头)是平坦且旋转的,而第二层(汽车图标)不是平坦且不旋转的。

有没有办法制作一个带有不同选项的双层标记图标或类似的东西?

推荐答案

为此,您需要两个点-旋转中心(参见图1):

图1-旋转中心点

P1-标记"平"部分的旋转中心;

P2-标记的非平坦部分的旋转中心。

因此,不可能通过默认标记旋转内部"非平坦"零件--它们只有一个旋转中心点--P1。复合图形P2坐标的确定也比较困难:需要精确读取可绘制图形的内部pathData坐标、包围框、中心点计算等。

但如果您有单独的占位符和汽车可绘制项,则不需要制作两层标记图标:您可以将内部图标(图1上的P2)的旋转中心确定为占位符(外部"平坦")和内部图标之间的偏移量,并且可以通过在地图画布上自定义绘制每个可绘制项(占位符需要旋转绘制)来实现旋转。

TLDR;

例如,占位符可绘制(icon_vehicle_marker.xml),如:

<vector android:height="24dp" android:viewportHeight="511.999"
    android:viewportWidth="511.999" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#006DF0" android:pathData="M405.961,62.116C365.906,22.06 312.649,0 256,0c-56.648,0 -109.905,22.06 -149.962,62.116C64.694,103.46 44.023,157.77 44.023,212.077s20.672,108.617 62.016,149.961L256,511.999L405.96,362.037c41.345,-41.345 62.016,-95.653 62.016,-149.961C467.976,157.77 447.306,103.461 405.961,62.116zM384.751,340.828L256,469.579L127.249,340.828c-35.497,-35.497 -53.244,-82.124 -53.244,-128.751s17.748,-93.255 53.244,-128.751C161.64,48.936 207.365,29.996 256,29.996c48.636,0 94.36,18.94 128.751,53.33c35.497,35.497 53.245,82.124 53.245,128.751S420.247,305.331 384.751,340.828z"/>
</vector>

和内车可抽屉(icon_car.xml),如:

<vector android:height="24dp" android:viewportHeight="459"
    android:viewportWidth="459" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#006DF0" android:pathData="M405.45,51c-5.101,-15.3 -20.4,-25.5 -35.7,-25.5H89.25c-17.85,0 -30.6,10.2 -35.7,25.5L0,204v204c0,15.3 10.2,25.5 25.5,25.5H51c15.3,0 25.5,-10.2 25.5,-25.5v-25.5h306V408c0,15.3 10.2,25.5 25.5,25.5h25.5c15.3,0 25.5,-10.2 25.5,-25.5V204L405.45,51zM89.25,306C68.85,306 51,288.15 51,267.75s17.85,-38.25 38.25,-38.25s38.25,17.85 38.25,38.25S109.65,306 89.25,306zM369.75,306c-20.4,0 -38.25,-17.85 -38.25,-38.25s17.85,-38.25 38.25,-38.25S408,247.35 408,267.75S390.15,306 369.75,306zM51,178.5L89.25,63.75h280.5L408,178.5H51z"/>
</vector>

使用MarkersMapView自定义视图,如:

public class MarkersMapView extends MapView implements OnMapReadyCallback {

    private OnMapReadyCallback mMapReadyCallback;
    private GoogleMap mGoogleMap;
    private Marker mMarker;

    private int mPlaceholderWidth = 150;
    private int mPlaceholderHeight = 150;

    private int mCarWidth = 75;
    private int mCarHeight = 75;
    private int mCarOffset = 90;

    private Drawable mPlaceholderDrawable;
    private Drawable mCarDrawable;

    public MarkersMapView(@NonNull Context context) {
        super(context);
        init(context);
    }

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

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

    public MarkersMapView(@NonNull Context context, @Nullable GoogleMapOptions options) {
        super(context, options);
        init(context);
    }


    @Override
    public void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        canvas.save();
        drawMarker(canvas);
        canvas.restore();
    }


    private void init(Context context) {
        setWillNotDraw(false);

        mPlaceholderDrawable = ContextCompat.getDrawable(context, R.drawable.icon_vehicle_marker);
        mPlaceholderDrawable.setBounds(0, 0 , mPlaceholderWidth, mPlaceholderHeight);

        mCarDrawable = ContextCompat.getDrawable(context, R.drawable.icon_car);
        mCarDrawable.setBounds(0, 0 , mCarWidth, mCarHeight);

        postInvalidate();
    }


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

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;
        mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
            @Override
            public void onCameraMove() {
                invalidate();
            }
        });
        if (mMapReadyCallback != null) {
            mMapReadyCallback.onMapReady(googleMap);
        }
    }


    private void drawMarker(Canvas canvas) {
        if (mGoogleMap == null || mMarker == null) {
            return;
        }


        Projection mapProjection = mGoogleMap.getProjection();

        // get screen coordinates of marker
        final Point pointMarker = mapProjection.toScreenLocation(mMarker.getPosition());

        canvas.save();
        // move origin to screen coordinates of marker shifted by placeholder icon sizes
        canvas.translate(pointMarker.x - mPlaceholderWidth / 2, pointMarker.y - mPlaceholderHeight);
        // rotate canvas according bearing of GoogleMap camera view
        canvas.rotate(-mGoogleMap.getCameraPosition().bearing, mPlaceholderWidth / 2, mPlaceholderHeight);
        mPlaceholderDrawable.draw(canvas);
        // revert origin back
        canvas.restore();

        // calculate position of inner icon center point
        float dx = (float) (mCarOffset * Math.sin(Math.toRadians(-mGoogleMap.getCameraPosition().bearing))) - mCarWidth / 2;
        float dy = (float) (-mCarOffset * Math.cos(Math.toRadians(-mGoogleMap.getCameraPosition().bearing))) - mCarHeight / 2;
        // move origin to screen coordinates of inner icon center point shifted by placeholder icon size
        canvas.translate(pointMarker.x + dx, pointMarker.y + dy);

        mCarDrawable.draw(canvas);
    }

    public void addMarker(MarkerOptions markerOptions) {
        removeMarker();
        mMarker = mGoogleMap.addMarker(markerOptions.visible(false));
    }

    public void removeMarker() {
        mGoogleMap.clear();
        mMarker = null;
    }

}

MainActivity.java点赞:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = MainActivity.class.getSimpleName();
    private static final String MAP_VIEW_BUNDLE_KEY = "MapViewBundleKey";
    private static final LatLng CAR = new LatLng(50.450311, 30.523730);

    private GoogleMap mGoogleMap;
    private MarkersMapView mMapView;

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

        Bundle mapViewBundle = null;
        if (savedInstanceState != null) {
            mapViewBundle = savedInstanceState.getBundle(MAP_VIEW_BUNDLE_KEY);
        }

        mMapView = (MarkersMapView) findViewById(R.id.mapview);
        mMapView.onCreate(mapViewBundle);
        mMapView.getMapAsync(new OnMapReadyCallback() {
            @Override
            public void onMapReady(GoogleMap googleMap) {
                mGoogleMap = googleMap;

                mMapView.addMarker(new MarkerOptions()
                        .position(CAR)
                        .flat(true)
                        .draggable(false));
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        mMapView.onResume();
    }

    @Override
    protected void onStart() {
        super.onStart();
        mMapView.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();
        mMapView.onStop();
    }
    @Override
    protected void onPause() {
        mMapView.onPause();
        super.onPause();
    }
    @Override
    protected void onDestroy() {
        mMapView.onDestroy();
        super.onDestroy();
    }
    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mMapView.onLowMemory();
    }
}

activity_main.xml点赞:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="activities.MainActivity">

    <{YOUR_PACKAGE_NAME}.MarkersMapView
        android:id="@+id/mapview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

您将看到类似的内容:

mCarOffset-在标记的"占位符"和"内部"图标上测量并硬编码的P1-P2距离。

NB!这只是一个标记的演示。例如,如果您有许多(数百个)标记,您应该确定应该准确地绘制哪些标记以提高性能。

这篇关于在GoogleMap中旋转两层标记图标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆