【高德地图】Android高德地图绘制标记点Marker

📖第4章 Android高德地图绘制标记点Marker

      • [✅绘制默认 Marker](#✅绘制默认 Marker)
      • ✅绘制多个Marker
      • [✅绘制自定义 Marker](#✅绘制自定义 Marker)
      • ✅Marker点击事件
      • ✅Marker动画效果
      • ✅Marker拖拽事件
      • [✅绘制默认 Infowindow](#✅绘制默认 Infowindow)
        • [🚩隐藏InfoWindow 弹框](#🚩隐藏InfoWindow 弹框)
      • [✅绘制自定义 InfoWindow](#✅绘制自定义 InfoWindow)
        • [🚩实现 InfoWindow 样式和内容](#🚩实现 InfoWindow 样式和内容)
        • [🚩可触发的 InfoWindow 事件](#🚩可触发的 InfoWindow 事件)
        • [🚩自定义复杂的 InfoWindow](#🚩自定义复杂的 InfoWindow)

✅绘制默认 Marker

效果如下图:

通过aMap.addMarker()来添加标记点marker,而经纬度等信息需要通过MarkerOptions来设置,示例代码如下:

java 复制代码
 //marker标记物
LatLng latLng = new LatLng(31.042119,121.410428);
 final Marker marker = aMap.addMarker(new MarkerOptions().position(latLng).title("测试地点").snippet("这里是测试内容"));

Marker 常用属性

名称 说明
position 在地图上标记位置的经纬度值。必填参数
title 点标记的标题
snippet 点标记的内容
draggable 点标记是否可拖拽
visible 点标记是否可见
anchor 点标记的锚点
alpha 点的透明度

anchor锚点可以精确控制标记图标相对于标记点(经纬度)的位置,以满足不同场景下的需求。比如您可能希望将锚点设置为标记图标的其他部分,例如顶部中心或左侧中心。默认锚点位置是底部中心

java 复制代码
anchor(0.0f, 0.5f); // 左侧中心
anchor(1.0f, 0.5f); // 右部中心
anchor(1.0f, 1.0f); // 底部右侧
anchor(0.5f, 0.0f); // 顶部中心

alpha透明度是用来表示对象的可见度或不透明度的属性。应用场景:

  1. 标记动画:实现标记的淡入淡出效果,以改善用户体验
java 复制代码
// 创建标记并设置透明度为0.5
MarkerOptions markerOptions = new MarkerOptions()
        .position(new LatLng(latitude, longitude))
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_icon))
        .alpha(0.5f); // 设置透明度为0.5
Marker marker = aMap.addMarker(markerOptions);

// 在动画中逐渐将透明度变为1.0
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(marker, "alpha", 0.5f, 1.0f);
alphaAnimator.setDuration(1000);
alphaAnimator.start();
  1. 突出显示标记: 在一组标记中突出显示特定的标记,可以使目标标记更加显眼。
java 复制代码
// 创建多个标记
MarkerOptions targetMarkerOptions = new MarkerOptions()
        .position(new LatLng(targetLatitude, targetLongitude))
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.target_marker_icon))
        .alpha(1.0f); // 目标标记的透明度为1.0
Marker targetMarker = aMap.addMarker(targetMarkerOptions);

MarkerOptions otherMarkerOptions = new MarkerOptions()
        .position(new LatLng(otherLatitude, otherLongitude))
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.other_marker_icon))
        .alpha(0.5f); // 其他标记的透明度为0.5
Marker otherMarker = aMap.addMarker(otherMarkerOptions);
  1. 动态显示与隐藏:将透明度设置为0.0时,标记将完全不可见,而设置为1.0时,则完全可见。
java 复制代码
// 创建标记并设置透明度为0.0,标记开始时不可见
MarkerOptions markerOptions = new MarkerOptions()
        .position(new LatLng(latitude, longitude))
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_icon))
        .alpha(0.0f); // 设置透明度为0.0
Marker marker = aMap.addMarker(markerOptions);

// 在动画中逐渐将透明度变为1.0,标记逐渐变得可见
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(marker, "alpha", 0.0f, 1.0f);
alphaAnimator.setDuration(1000);
alphaAnimator.start();

✅绘制多个Marker

效果如下图:

不管是创建默认的Marker还是自定义的Marker都一样,都是通过MarkerOptions设置Marker的信息,再通过aMap.addMarker(markerOption)在地图上添加。

示例代码如下:

java 复制代码
        //样本数据
        List<LatLng> positon = new ArrayList<>();
        positon.add(new LatLng(31.041742,121.411517));
        positon.add(new LatLng(31.041370,121.411699));
        positon.add(new LatLng(31.041563,121.412198));
        //绘制自定义marker
        MarkerOptions options = new MarkerOptions();
        for (int i = 0; i < positon.size(); i++) {
            options.position(positon.get(i));
            options.title("测试"+i);
            options.snippet("内容"+i);
            aMap.addMarker(options);
        }

✅绘制自定义 Marker

效果如下图:

绘制自定义 Marker的自定义icon图标是通过BitmapDescriptorFactory来处理,它能将图标资源文件转换成位图(Bitmap)对象,以便在地图上使用。示例代码如下:

java 复制代码
        //绘制自定义marker
        LatLng latLng2 = new LatLng(31.041991,121.409628);
        MarkerOptions markerOption = new MarkerOptions();
        markerOption.position(latLng2);
        markerOption.title("测试2").snippet("我是自定义marker");
        markerOption.draggable(true);//设置Marker可拖动
        markerOption.icon(BitmapDescriptorFactory.fromBitmap(BitmapFactory
                .decodeResource(getResources(),R.drawable.icon_marker_orange)));
        markerOption.setFlat(false);//设置marker平贴地图效果
        aMap.addMarker(markerOption);

至于icon图标可以在阿里巴巴矢量图标库里面下载png格式的图片即可。

🚩扩展:在自定义的marker中绘制文字等其他信息

应用场景:需要在地图上看见该标记点中的数据信息,可以是姓名简称,数字等信息。 效果如下图:

一共两个步骤:

  • 绘制带文本的图片,格式为BitmapDescriptor类型
  • 在地图上添加标记点
java 复制代码
        //绘制自定义带文字的marker
        BitmapDescriptor withDataIcon = drawIcon(R.drawable.icon_marker_orange, "李", Color.WHITE);
        LatLng latLng2 = new LatLng(31.041991,121.409628);
        MarkerOptions markerOption = new MarkerOptions();
        markerOption.position(latLng2);
        markerOption.title("测试").snippet("我是携带数据的marker");
        markerOption.draggable(true);//设置Marker可拖动
        markerOption.icon(withDataIcon);
        markerOption.setFlat(false);//设置marker平贴地图效果
        aMap.addMarker(markerOption);

drawIcon方法如下:

java 复制代码
    /**
     * 绘制带文字的marker
     * @param markerStyle 图片资源
     * @param text        文字
     * @param textColor   文字颜色
     * @return
     */
    private BitmapDescriptor drawIcon(int markerStyle, String text, int textColor) {
        Bitmap bitmap = null;
        BitmapDescriptor icon = null;
        try {
            bitmap = BitmapFactory.decodeResource(getResources(), markerStyle);//图片转bitmap位图
            int markerStyleWidth = bitmap.getWidth();//获取bitmap位图的宽
            int markerStyleHeight = bitmap.getHeight();//获取bitmap位图的高
            Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);//复制Bitmap对象
            Canvas canvas = new Canvas(mutableBitmap); //创建Canvas对象
            Paint paint = new Paint();//创建Paint对象,用于定义绘制文本的样式
            paint.setColor(textColor);//设置文字颜色
            paint.setTextSize(getResources().getDimensionPixelSize(R.dimen.text_size));//设置文字大小
            //获取文本边界
            Rect textBounds = new Rect();
            paint.getTextBounds(text, 0, text.length(), textBounds);
            int textWidth = textBounds.width();//文本宽度
            int textHeight = textBounds.height();//文本高度
            //计算文字在图片上的坐标,使其在图片居中位置
            float x = (markerStyleWidth - textWidth) / 2.0f;//x表示绘制文本起始点的横坐标,从左开始
            float y = (markerStyleHeight + textHeight) / 2.0f - 20;//x表示绘制文本起始点的纵坐标,从顶部开始
            canvas.drawText(text, x, y, paint); //使用Canvas绘制文本
            icon = BitmapDescriptorFactory.fromBitmap(mutableBitmap);// 最后将Bitmap 转换为 BitmapDescriptor
            return icon;
        } finally {
            if (bitmap != null){
                bitmap.recycle();
            }
            if (icon != null){
                icon.recycle();
            }
        }
    }

注意:

  • BitmapBitmapDescriptor是一个占用内存的对象,需要及时回收以防止内存泄漏。虽然Java有垃圾回收机制,但它是在适当的时机,例如在内存紧张或空闲时,扫描不再被引用的对象并将其释放,在某些情况下,手动释放资源仍然是一个良好的习惯。
  • R.dimen.text_size是在values文件下的dimens.xml资源文件中定义的,如果你没有则创建一个并添加下面代码。
xml 复制代码
<resources>
    <dimen name="text_size">14sp</dimen>
</resources>

✅Marker点击事件

点击 Marker 时会回调AMap.OnMarkerClickListener,监听器的实现示例如下:

java 复制代码
 //设置marker点击事件
 aMap.setOnMarkerClickListener(this);

重写onMarkerClick方法

java 复制代码
    /**
     * marker 点击监听事件
     * 返回 true 则表示接口已响应事件,否则返回false
     * @param marker
     * @return
     */
    @Override
    public boolean onMarkerClick(Marker marker) {
        return false;
    }

✅Marker动画效果

将动画效果放在点击marker时可以更好看到变化,自地图 SDK V4.0.0 版本起,SDK 提供了给 Marker 设置动画的方法,具体实现方法如下:

java 复制代码
    /**
     * marker 点击监听事件
     * 返回 true 则表示接口已响应事件,否则返回false
     * @param marker
     * @return
     */
    @Override
    public boolean onMarkerClick(Marker marker) {
        //180度旋转动画
        Animation animation = new RotateAnimation(marker.getRotateAngle(),marker.getRotateAngle()+180,0,0,0);
        long duration = 1000L;
        animation.setDuration(duration);
        animation.setInterpolator(new LinearInterpolator());
        marker.setAnimation(animation);
        marker.startAnimation();
        return false;
    }

✅Marker拖拽事件

拖拽 Marker 时会回调AMap.OnMarkerDragListener,监听器的实现示例如下:

java 复制代码
//设置marker拖拽监听事件
 aMap.setOnMarkerDragListener(this);
java 复制代码
    /**
     * 当marker开始被拖动时回调此方法, 这个marker的位置可以通过getPosition()方法返回。
     * @param marker
     */
    @Override
    public void onMarkerDragStart(Marker marker) {
        Log.d("MainActivity", "Start: "+marker.getPosition());
    }
    /**
     *  在marker拖动过程中回调此方法, 这个marker的位置可以通过getPosition()方法返回。
     * @param marker
     */
    @Override
    public void onMarkerDrag(Marker marker) {
        Log.d("MainActivity", "Drag: "+marker.getPosition());
    }
    /**
     * 在marker拖动完成后回调此方法, 这个marker的位置可以通过getPosition()方法返回。
     * @param marker
     */
    @Override
    public void onMarkerDragEnd(Marker marker) {
        Log.d("MainActivity", "End: "+marker.getPosition());
    }

✅绘制默认 Infowindow

默认 Infowindow是不用创建的,当我们创建marker时自带有的,SDK 为用户提供了默认的 InfoWindow 样式,只显示 Marker 对象的两个属性,一个是 title 和另一个 snippet

调用 Marker 类的 showInfoWindow()hideInfoWindow() 方法可以控制显示和隐藏。

当改变 Marker 的 title 和 snippet 属性时,再次调用 showInfoWindow(),可以更新 InfoWindow 显示内容。

🚩隐藏InfoWindow 弹框

在什么时候去隐藏InfoWindow 弹框,一般情况可以在点击map地图的其他地方关闭它,实现方式如下:

  • 首先设置markermap点击监听事件
java 复制代码
//设置marker点击事件
aMap.setOnMarkerClickListener(this);
//地图点击监听事件
aMap.setOnMapClickListener(this);
  • 然后在marker点击事件中记录当前点击的markerInfowindow是否弹框的布尔值
java 复制代码
 private Marker current;//记录当前点击的marker
private boolean isMarkerClicked = false;//判断是否Infowindow弹框
@Override
    public boolean onMarkerClick(Marker marker) {
        current = marker;
        isMarkerClicked = true;
        return false;
    }
  • 最后在onMapClick地图点击事件中隐藏Infowindow弹框
java 复制代码
    /**
     * map地图点击监听事件
     */
    @Override
    public void onMapClick(LatLng latLng) {
        if (!isMarkerClicked) {
            if (current != null && current.isInfoWindowShown()) {
                current.hideInfoWindow();//隐藏当前Infowindow弹框
            }
        }
        isMarkerClicked = false; // 重置标记状态
    }

✅绘制自定义 InfoWindow

实现 InfoWindowAdapter接口,其中有两个方法需要实现,依次来看一下:

java 复制代码
public interface InfoWindowAdapter {
        View getInfoWindow(Marker marker);
        View getInfoContents(Marker marker);
}

View getInfoWindow(Marker marker)

  • 当实现此方法并返回有效值时(返回值不为空,则视为有效),SDK 将不会使用默认的样式,而采用此方法返回的样式(即 View)。默认会将Marker 的 title 和 snippet 显示到 InfoWindow 中。
  • 如果此时修改了 Marker 的 title 或者 snippet 内容,再次调用类 Marker 的 showInfoWindow() 方法,InfoWindow 内容不会更新。
  • 自定义 InfoWindow 之后所有的内容更新都需要用户自己完成。
  • 当调用 Marker 类的 showInfoWindow() 方法时,SDK 会调用 getInfoWindow(Marker marker) 方法和 getInfoContents(Marker marker) 方法(之后会提到),在这些方法中更新 InfoWindow 的内容即可。

注意:如果此方法返回的 View 没有设置 InfoWindow 背景图,SDK 会默认添加一个背景图。

View getInfoContents(Marker marker)

此方法和 getInfoWindow(Marker marker) 方法的实质是一样的,唯一的区别是:

  • 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框。

简而言之,getInfoContents(Marker marker) 只允许你自定义 InfoWindow 的内容,而不能改变整个窗口的外观和边框。SDK 会在你自定义的内容外面添加一个默认的边框。这可能是为了确保 InfoWindow 在地图上有一致的外观,以保持用户体验的统一性。如果你希望完全自定义整个 InfoWindow 的外观,包括边框,那么应该使用 getInfoWindow(Marker marker) 方法。

🚩实现 InfoWindow 样式和内容

实现 InfoWindow 样式和内容的步骤如下:

  • 设置InfoWindow适配器
  • getInfoWindow返回一个自定义View组件 = R.layout.custom_info_window
java 复制代码
implements AMap.InfoWindowAdapter//实现接口

 aMap.setInfoWindowAdapter(this);//设置InfoWindow适配器

实现getInfoWindow和getInfoContents方法

java 复制代码
    View infoWindow = null;
    @Override
    public View getInfoWindow(Marker marker) {
        if (infoWindow == null) {
            infoWindow = LayoutInflater.from(this).inflate(R.layout.custom_info_window, null);
        }
        render(marker, infoWindow);
        return infoWindow;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null;
    }
    public void render(Marker marker, View view) {
        //如果想修改自定义Infow中内容,请通过view找到它并修改
        String title = marker.getTitle();
        TextView titleUi = view.findViewById(R.id.title);
        titleUi.setText(title);
        String snippet = marker.getSnippet();
        TextView snippetUi = view.findViewById(R.id.snippet);
        snippetUi.setText(snippet);
    }

R.layout.custom_info_window组件:

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:gravity="center"
    android:orientation="vertical"
    >
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="17sp"
        android:textColor="#72db0f"
        android:text="标题"
        />
    <TextView
        android:id="@+id/snippet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="17sp"
        android:textColor="#db0f00"
        android:text="详细内容"
        />
</LinearLayout>
🚩可触发的 InfoWindow 事件

点击 InfoWindow 时会回调 AMap.OnInfoWindowClickListener,监听器的实现示例如下:

java 复制代码
OnInfoWindowClickListener listener = new OnInfoWindowClickListener() {
    @Override
    public void onInfoWindowClick(Marker marker) {
        
        marker.setTitle("infowindow clicked");
    }
};

//绑定信息窗点击事件
aMap.setOnInfoWindowClickListener(listener);

简单点说就是可以自定义点击 InfoWindow 后的行为,例如改变标题、展示更多信息或触发其他操作。它有哪些使用场景和用途:

  • 刷新 InfoWindow 内容: 在点击事件中,您可以修改 InfoWindow 的内容,使其动态刷新,显示最新的信息。这对于实时更新的信息非常有用。
  • **交互式地图体验:**例如点击时显示更多的内容、点击后关闭InfoWindow弹框,marker.hideInfoWindow()即可。
  • **与标记点关联的操作:**例如,在地图上显示商家的标记点,点击 InfoWindow 可以跳转到商家详情页面。

等等还要其他的,这里就举例这几种。

🚩自定义复杂的 InfoWindow

根据需求,你可能需求对标记点进行各种操作,如下图:

其实绘制自定义 InfoWindow本质上就是两步,先设置InfoWindow适配器,其次在view组件中自定义要显示的样式或按钮。

在这种自定义可能会遇到居中显示问题,如何点击标点时让其在屏幕中心,或者在屏幕中心下方一点点使其能都刚好在屏幕中心完全显示。只需在onMarkerClick点击事件中实现如下逻辑:

  • marker位置坐标下移一小段距离显示
  • 注意实现onMarkerClick前需要 aMap.setOnMarkerClickListener(this);设置
java 复制代码
    @Override
    public boolean onMarkerClick(Marker marker) {
        // 当前点击的marker位置坐标
        LatLng markerLatLng = marker.getPosition();
        // 计算新坐标(下移一小段距离)
        double offsetLat = 0.003; 
        LatLng newCenterLatLng = new LatLng(markerLatLng.latitude + offsetLat, markerLatLng.longitude);
        // 创建一个新的 CameraPosition,设置新的方向为 0(北方向)
        CameraPosition newPosition = new CameraPosition.Builder()
                .target(newCenterLatLng)
                .bearing(0) // 将方向设置为 0(北方向)
                .zoom(15) // 设置缩放级别
                .build();
        // 移动地图中心点
        aMap.animateCamera(CameraUpdateFactory.newCameraPosition(newPosition));

        return true; // 返回 true 表示消费了点击事件,不再传递给其他监听器

    }

第1,2章 Android搭建3D高德地图详细教

第 3 章 初始化定位并显示小蓝点

第 4 章Android高德地图绘制标记点Marker

第 5 章Android高德地图控件交互详细介绍

相关推荐
南国樗里疾31 分钟前
Android 14 解决打开app出现不兼容弹窗的问题
android
IT小码哥丶34 分钟前
HarmonyOS实战:自定义时间选择器
android·harmonyos
liulangrenaaa34 分钟前
C语言实现android/linux按键模拟
android·linux·c语言
LB21121 小时前
黑马 javaweb Day07 MySQL --DQL(查询)语句
android·数据库·mysql
CYRUS STUDIO1 小时前
FART 自动化脱壳框架简介与脱壳点的选择
android·驱动开发·自动化·逆向·源码阅读·脱壳
CYRUS STUDIO3 小时前
FART 主动调用组件设计和源码分析
android·逆向·源码分析·fart·脱壳
带刺的坐椅5 小时前
高德地图 MCP,可用 Java SolonMCP 接入(支持 java8, java11, java17, java21)
java·ai·solon·高德地图·lbs·mcp
zimoyin8 小时前
kotlin Android AccessibilityService 无障碍入门
android·开发语言·kotlin
韩仔搭建20 小时前
第二章:安卓端启动流程详解与疑难杂症调试手册
android·ui·娱乐
A-花开堪折20 小时前
Android7 Input(七)App与input系统服务建立连接
android