当前位置: 首页 > article >正文

高德地图SDK Android版开发 10 InfoWindow

高德地图SDK Android版开发 10 InfoWindow

  • 前言
  • 相关类和方法
    • 默认样式
      • Marker类
      • AMap类
      • AMap.OnInfoWindowClickListener 接口
    • 自定义样式(视图)
      • AMap 类
      • AMap.ImageInfoWindowAdapter 接口
    • 自定义样式(Image)
      • AMap.ImageInfoWindowAdapter 接口
  • 示例
    • 界面布局
    • MapInfoWindow类
      • 常量
      • 成员变量
      • 初始化
      • 创建与移除覆盖物
      • 设置属性
      • 自定义样式
      • 加载与移除地图
    • MapInfoWindowActivity 类
      • 控件响应事件
    • 运行效果图

前言

前文介绍高德地图添加Marker覆盖物的使用方法,Marker结合InfoWindow可展示更详尽的信息。本文将介绍以下内容:

  1. 使用SDK默认样式显示InfoWindow的方法;
  2. 自定义InfoWindow样式的方法。

相关类和方法

默认样式

  • 在高德地图SDK中,InfoWindow 是点标记的一部分,默认的 Infowindow 只显示 Marker 对象的两个属性,一个是 title 和另一个 snippet。
  • SDK 为用户提供了默认的 InfoWindow 样式,调用 Marker 类的 showInfoWindow() hideInfoWindow() 方法可以控制显示和隐藏。
  • 当改变 Markertitlesnippet 属性时,再次调用 showInfoWindow(),可以更新 InfoWindow 显示内容。

Marker类

  • 标题、文字片段和附加信息的方法
类型方法说明
StringgetSnippet()获取Marker 覆盖物的文字片段。
StringgetTitle()获取Marker 覆盖物的标题。
ObjectgetObject()获取Marker覆盖物的附加信息对象,即自定义的Marker的属性。
voidsetSnippet(String snippet)设置Marker 覆盖物的文字片段。
voidsetTitle(String title)设置Marker 覆盖物的标题。
voidsetObject(Object object)设置Marker覆盖物的附加信息对象。
  • InfoWindow的方法
类型方法说明
booleanisInfoWindowEnable()获取Marker覆盖物是否允许InfoWindow显示,
可以通过 Marker.setInfoWindowEnable(boolean) 进行设置
voidsetInfoWindowEnable(boolean enabled)设置Marker覆盖物的InfoWindow是否允许显示,默认为true。
设置为false之后, 调用Marker.showInfoWindow() 将不会生效
booleanisInfoWindowShown()返回Marker覆盖物的信息窗口是否显示,true: 显示,false: 不显示。
voidshowInfoWindow()显示 Marker 覆盖物的信息窗口。
voidhideInfoWindow()隐藏Marker覆盖物的信息窗口。

AMap类

类型方法说明
voidsetOnInfoWindowClickListener(AMap.OnInfoWindowClickListener listener)设置marker的信息窗口点击事件监听接口。

AMap.OnInfoWindowClickListener 接口

public interface OnInfoWindowClickListener {
    void onInfoWindowClick(Marker marker);
}

自定义样式(视图)

AMap 类

类型方法说明
voidsetInfoWindowAdapter(AMap.InfoWindowAdapter adapter)设置marker的信息窗口定制接口。

AMap.ImageInfoWindowAdapter 接口

用来定制Marker的信息窗口。

类型方法说明
android.view.ViewgetInfoWindow(Marker marker)定制展示marker信息的View。(注:可自定义背景
android.view.ViewgetInfoContents(Marker marker)定制展示marker信息的View。(注:使用默认背景
public interface InfoWindowAdapter {
    // 如果返回的View不为空且View的background不为null,则直接使用它来展示marker的信息。
    // 如果backgound为null,SDK内部会给这个View设置一个默认的background。
    // 如果这个方法返回null,内容将会从getInfoContents(Marker)方法获取。
    View getInfoWindow(Marker marker);

    // 如果返回的View不为空且View的background不为null,则直接使用它来展示marker的信息。
    // 如果backgound为null,SDK内部会给这个View设置一个默认的background。
    // 如果这个方法返回null,将使用内置的一个默认的View来展示marker的信息。
    View getInfoContents(Marker marker);
}

触发机制

  • 默认情况下,当单击某个marker时,如果该marker的Title和Snippet不为空,则会触发getInfoWindow和getInfoContents回调。
  • 另外,通过**调用Marker.showInfoWindow()**同样可以触发上面两个回调。

返回null的处理逻辑

  • 自5.2.1开始,如果getInfoWindow(Marker) 和 getInfoContents(Marker) 均返回null,将不展示InfoWindow的信息

自定义样式(Image)

说明:此方法官方指南未介绍,来自参考手册。(未做验证)

AMap.ImageInfoWindowAdapter 接口

«interface»
InfoWindowAdapter
«interface»
ImageInfoWindowAdapter
+long getInfoWindowUpdateTime()

用途:

用来实现marker与对应InfoWindow同步移动。

默认情况下,InfoWindow是一个View, 拖动地图的时候由于View 布局较慢,会有延迟的效果

为了解决此问题,新增AMap.ImageInfoWindowAdapter, InfoWindow会被转为图片,拖动地图时会跟随Marker

注意

使用ImageInfoWindowAdapter后InfoWindow作为View本身的功能被减弱,比如动态更新图片,播放Gif图片等等均无法使用。

如果想要动态的去更新infowindow内容,请务必仔细看看此接口的更新机制

更新机制

设置此接口返回值之后,会定期(默认周期无穷大)调用一个 getInfoWindow(Marker)将View转换为图片

由于将View转成图片会比较耗时,不能一直调用,而设置时间间隔可以减少一定的耗时。

调用Marker.showInfoWindow() 也可以触发调用 AMap.InfoWindowAdapter.getInfoWindow(Marker) 并将View转换为图片。

类型方法说明
longgetInfoWindowUpdateTime()自定义整个信息窗口属性间隔时间。单位为 ms

方法说明

  • 如果返回值 小于或等于 0,则认为是无穷大。
  • 如果返回值 (0,100] , 则认为是100(如果频繁将View转成图片,内存抖动会很严重,建议这个值不要太低)。
  • 如果这个想实现更小的时间间隔或者不想受这个接口约束,可以保持返回默认值,并自行设置计时器。

示例

界面布局

在这里插入图片描述

  • 布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="MapInfoWindowActivity">

    <com.amap.api.maps.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/bottomView"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.appcompat.widget.LinearLayoutCompat
        android:id="@+id/bottomView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@id/map">

        <RadioGroup
            android:id="@+id/RadioGroup"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/background_dark"
            android:gravity="center_horizontal"
            android:orientation="horizontal"
            android:paddingHorizontal="10dp">

            <RadioButton
                android:id="@+id/simpleMode"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:checked="true"
                android:onClick="setMarkerFlag"
                android:text="简单"
                android:textColor="@color/white"
                android:textStyle="bold" />

            <RadioButton
                android:id="@+id/adapter_window_mode"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="setMarkerFlag"
                android:text="适配器(窗口)"
                android:textColor="@color/white"
                android:textStyle="bold" />

            <RadioButton
                android:id="@+id/adapter_content_mode"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:onClick="setMarkerFlag"
                android:text="适配器(内容)"
                android:textColor="@color/white"
                android:textStyle="bold" />

        </RadioGroup>

    </androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>

MapInfoWindow类

  • 以下是MapInfoWIndows部分代码

常量

public static final String SIMPlE_MODE = "SimpleMode";
public static final String ADAPTER_WINDOW_MODE = "AdapterWindowMode";
public static final String ADAPTER_CONTENT_MODE = "AdapterContentMode";

成员变量

// 覆盖物列表
List<BaseOverlay> overlays = new ArrayList<>();
// 选中的状态
String selectedFlag = SIMPlE_MODE;
// 气泡图标
ArrayList<BitmapDescriptor> bitmaps = new ArrayList<>();

初始化

int[] drawableIds = BubbleIcons.Number;
for (int drawableId : drawableIds) {
    BitmapDescriptor bitmap = BitmapDescriptorFactory.fromResource(drawableId);
    bitmaps.add(bitmap);
}
initEvent();
private void initEvent() {
    // 设置marker的信息窗口点击事件监听接口。
    map.setOnInfoWindowClickListener(new AMap.OnInfoWindowClickListener() {
        @Override
        public void onInfoWindowClick(Marker marker) {
            // 隐藏Marker覆盖物的信息窗口。
            marker.hideInfoWindow();
        }
    });
}

创建与移除覆盖物

public void addMarkers() {
    // 构造大量坐标数据
    List<LatLng> points = new ArrayList<>();
    points.add(new LatLng(39.97923, 116.357428));
    points.add(new LatLng(39.94923, 116.397428));
    points.add(new LatLng(39.97923, 116.437428));
    points.add(new LatLng(39.92353, 116.490705));
    points.add(new LatLng(40.023537, 116.289429));
    points.add(new LatLng(40.022211, 116.406137));

    // 创建OverlayOptions的集合
    ArrayList<MarkerOptions> optionsList = new ArrayList<>();
    for (int i = 0; i < points.size(); ++i) {
        // 创建OverlayOptions属性
        MarkerOptions option = new MarkerOptions()
                .position(points.get(i))
                .icon(bitmaps.get(i))
                .title("标题" + (i + 1))
                .snippet("详细信息" + (i + 1));
        // 将OverlayOptions添加到list
        optionsList.add(option);
    }

    boolean moveToCenter = true;
    // 在地图上添一组图片标记(marker)对象,
    // 并设置是否改变地图状态以至于所有的marker对象都在当前地图可视区域范围内显示。
    ArrayList<Marker> newOverlays = map.addMarkers(optionsList, moveToCenter);
    overlays.addAll(newOverlays);
}

public void removeOverlay() {
    // 从地图上删除所有的覆盖物(marker,circle,polyline 等对象),
    // 但myLocationOverlay(内置定位覆盖物)除外。
//        boolean isKeepMyLocationOverlay = true;
//        map.clear(isKeepMyLocationOverlay);

    for (BaseOverlay overlay : overlays) {
        if (overlay instanceof Marker) {
            Marker marker = (Marker) overlay;
            marker.hideInfoWindow();
        }
    }
    overlays.clear();
}

设置属性

public void setFlag(String flag) {
    selectedFlag = flag;

    switch (selectedFlag) {
    case SIMPlE_MODE:
        map.setInfoWindowAdapter(null);
        break;
    case ADAPTER_WINDOW_MODE:
        map.setInfoWindowAdapter(new WindowModeAdapter());
        break;
    case ADAPTER_CONTENT_MODE:
        map.setInfoWindowAdapter(new ContentModeAdapter());
        break;
    }
}

说明:自定义样式参考官方Demo,WindowModeAdapterContentModeAdapter为自定义两个适配器。代码和布局见附录。

自定义样式

  • WindowModeAdapter

布局custom_info_window.xml (background+image+tItle+snippet)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:background="@drawable/custom_info_bubble"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/badge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff000000"
            android:textSize="14dp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff7f7f7f"
            android:textSize="14dp" />
    </LinearLayout>

</LinearLayout>

WindowModeAdapter

private class WindowModeAdapter implements AMap.InfoWindowAdapter {
    @Override
    public View getInfoWindow(Marker marker) {
        // 加载自定义布局文件作为InfoWindow的样式
        View view = LayoutInflater.from(context).inflate(R.layout.custom_info_window, null);
        render(marker, view);
        return view;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null;
    }
}
  • ContentModeAdapter

布局custom_info_contents.xml (image+tItle+snippet)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/badge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dp"
        android:adjustViewBounds="true" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff000000"
            android:textSize="14dp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="end"
            android:singleLine="true"
            android:textColor="#ff7f7f7f"
            android:textSize="14dp" />
    </LinearLayout>

</LinearLayout>

ContentModeAdapter

private class ContentModeAdapter implements AMap.InfoWindowAdapter {
    @Override
    public View getInfoWindow(Marker marker) {
        return null;
    }

    @Override
    public View getInfoContents(Marker marker) {
        // 加载自定义布局文件作为InfoWindow的样式
        View view = LayoutInflater.from(context).inflate(R.layout.custom_info_contents, null);
        render(marker, view);
        return view;
    }
}
  • render方法(设置image+title+snippet)
private void render(Marker marker, View view) {
    ImageView imageView = view.findViewById(R.id.badge);
    imageView.setImageResource(android.R.drawable.ic_menu_gallery);

    String title = marker.getTitle();
    TextView titleUi = view.findViewById(R.id.title);
    if (title != null) {
        SpannableString titleText = new SpannableString(title);
        titleText.setSpan(new ForegroundColorSpan(Color.RED), 0, titleText.length(), 0);
        titleUi.setTextSize(15);
        titleUi.setText(titleText);
    } else {
        titleUi.setText("");
    }

    String snippet = marker.getSnippet();
    TextView snippetUi = view.findViewById(R.id.snippet);
    if (snippet != null) {
        SpannableString snippetText = new SpannableString(snippet);
        snippetText.setSpan(new ForegroundColorSpan(Color.GREEN), 0, snippetText.length(), 0);
        snippetUi.setTextSize(20);
        snippetUi.setText(snippetText);
    } else {
        snippetUi.setText("");
    }
}

加载与移除地图

public void onMapLoaded() {
    addMarkers();
    setFlag(SIMPlE_MODE);
}

public void onMapDestroy() {
    removeOverlay();

    for (BitmapDescriptor bitmap : bitmaps) {
        bitmap.recycle();
    }
    bitmaps = null;
}

MapInfoWindowActivity 类

  • 以下是MapInfoWindowActivity类部分代码

控件响应事件

public void setMarkerFlag(View view) {
    boolean checked = ((RadioButton) view).isChecked();
    if (!checked)
        return;

    int id = view.getId();
    String flag;
    if (id == R.id.simpleMode)
        flag = MapInfoWindow.SIMPlE_MODE;
    else if (id == R.id.adapter_window_mode)
        flag = MapInfoWindow.ADAPTER_WINDOW_MODE;
    else if (id == R.id.adapter_content_mode)
        flag = MapInfoWindow.ADAPTER_CONTENT_MODE;
    else
        return;

    mapInfoWindow.setFlag(flag);
}

运行效果图

简单适配器(窗口)适配器(内容)
在这里插入图片描述在这里插入图片描述在这里插入图片描述
默认样式自定义:
background+image+title+snippet
自定义:
image+title+snippet

http://www.kler.cn/news/294197.html

相关文章:

  • 【Redis】Windows平台编译调试运行Redis,并附编译问题解决方案
  • 用python fastapi写一个http接口,使ros2机器人开始slam toolbox建图
  • @import导入样式以及scss变量应用与static目录
  • 4. GIS前端工程师岗位职责、技术要求和常见面试题
  • Windows 11的新游戏手柄键盘现在可让玩家使用Xbox手柄打字
  • UE引擎工具链
  • vue3+ant design vue实现表格导出(后端返回文件流类型导出)
  • 多线程的实现和成员方法
  • 2 php8.0 中开发一个websocket 聊天 表设计
  • 启动第一个docker容器
  • Vue——day11之生命周期
  • Java使用类加载器解决类冲突,多版本jar共存
  • MySQL5.7.36之高可用架构部署-MHA
  • 大数据-118 - Flink DataSet 基本介绍 核心特性 创建、转换、输出等
  • 探索 Zed 编辑器:速度与协作的巅峰之作
  • 怎麼實現爬蟲自動換代理-okeyproxy
  • 用idea写Spark程序时,想要在控制台打印日志?
  • CentOS7 部署 Zabbix 监控平台———监控网络设备,Linux 主机、Windows 主机
  • 启动Spring Boot报错
  • C++11中新引入的enum类型
  • 20240903软考架构-------软考111-115答案解析
  • 匈牙利算法实现(from scipy.optimize import linear_sum_assignment)
  • GNN中的Over-smoothing与Over-squashing问题
  • 使用SymbolGlyph和SymbolSpan在HarmonyOS中实现高级图标效果
  • 【扩散模型(十)】IP-Adapter 源码详解 4 - 训练细节、具体训了哪些层?
  • 新加坡裸机云多IP服务器特性
  • java-在idea中antrl的hello world
  • 63、Python之函数高级:装饰器缓存实战,优化递归函数的性能
  • Spring Boot启动卡在Root WebApplicationContext: initialization completed in...
  • TulingMember进销存系统