运行时更改标记图标

11

有没有一种在运行时更改Google Maps Android API v2标记图标而无需删除/重新添加我想要更改其图标的标记的方法? 我可以对其应用变换(如旋转)吗?

谢谢。


是的,如果该图标是由您自己制作并放置在项目的“res/drawable”文件夹中,则可以对其进行动画处理。有关动画处理,请参考开发指南 - BBonDoo
2
Marker在API v2的rev.7中新增了一个新功能。请参见Marker.setIcon - MaciejGórski
@MaciejGórski您好,您能告诉我如何将Google Map API更新到rev.7吗?我尝试使用该函数,但我的项目无法编译。 - GingerJim
@GingerJim,我刚刚在SDK管理器中更新了“Google Play服务”项目,并导入、编译并添加到主项目中,现在它可以在运行时更改标记图标。 - Balaji
6个回答

23

更新到Google Play服务Rev 7后,我能够轻松地在运行时更改标记图标,现在

Marker.setIcon(BitmapDescriptor icon)

可用了,以前我是通过删除和添加标记来更改其颜色。


如果我有多个引脚,并且更改所选引脚和未选引脚的颜色应该是默认的,那该怎么办?谢谢。 - dhiku
@dhiku,抱歉回复晚了,我不确定您的需求,当单击标记或标记信息窗口时,您将获得市场参考,因此您可以更改图标,如果您有不同的要求,还可以维护标记的HashMap并对其进行处理。FYI BitmapDescriptor green = BitmapDescriptorFactory.fromResource(R.drawable.marker_green);BitmapDescriptor blue = BitmapDescriptorFactory.fromResource(R.drawable.marker_gray); marker.setIcon(selected ? green : blue); - Balaji
@dhiku,现在我明白了你的需求,我认为你需要维护一个标记集合,即Set。 - Balaji

4

目前您不能在运行时更改标记,也不能对其应用旋转。

但是您可以使用一个变通方法 - 我正在使用 BlinkingMarker 类,其中我必须在运行时调整标记图像的不透明度。

现在唯一的解决方案是创建具有不同旋转角度的位图,然后定期添加/删除它们。这种解决方案的问题在于添加/删除标记会导致大量的内存分配,因此会导致不断进行垃圾回收。更好、更平滑的变通方法是预先创建所有图像,并将它们全部添加到地图中。之后,您可以使用 Marker.setVisible(boolean) 函数来显示当前需要的标记。

注意:在执行此操作之前,请测量您的位图,因为添加许多大型位图可能会导致应用程序的内存大小增长。

您可以在这里查看我的解决方法:https://github.com/balazsbalazs/blinking-marker-mapsv2

这是一个闪烁的标记(更改位图的不透明度),但您可以在相同的线上应用任何类型的变换。


3
文档对此问题非常清晰--
Icon
    A bitmap that's displayed in place of the default marker image. You can't change the icon once you've created the marker.
如果你想改变标记的外观,有几种选择。其中一种是,像你所说的那样,删除标记并添加另一个标记。另一种方法是在同一位置放置多个标记,并在任何给定时间切换可见的标记。你可以在使用图像创建标记之前对图像应用任何想要的转换(如旋转)。

1
我刚看到这篇文章,这个答案还有效吗?因为我发现我可以用 setIcon() 更改图标。 - Arch1tect

3
2013年9月Google Maps Android API v2发布中,现在为标记添加了一个新的setRotation()方法,以及一个新的setFlat()方法。
以下是Google对这些新功能的描述:

让您的标记有方向感

我们添加了一个标记旋转属性,允许您围绕其锚点旋转标记。新的平面属性允许您将标记放置在地图表面上,而不是弹出以面对相机。当地图被旋转或倾斜时,这两个新属性特别有用于指示罗盘方向。

这里有一篇文章描述这些新功能。

2
为了在运行时更改所选标记图标,只需添加以下代码:
      @Override
      public boolean onMarkerClick(Marker marker) {

       Marker.setIcon (BitmapDescriptor icon);
       }

1

仅适用于Android

在运行时更改标记的图标,我通过删除第186行中的“final”关键字,将图标变量从final更改为non-final

final BitmapDescriptor icon;

BitmapDescriptor icon;

请将第136行的标记构造函数从“const”更改为“non-const”:

const Marker({

Marker({

要更改软件包,您必须遵循此说明

使用google_maps_flutter存储库时,您会收到错误消息:“找不到pubspec.yaml”。 这是因为google_maps_flutter软件包位于存储库的子目录中。

要获取正确的依赖项,您必须在pubspec.yaml中添加软件包的特定路径:

 dependencies:
  # google_maps_flutter: ^2.1.1
  google_maps_flutter:
    git:
      url: https://github.com/[username]/plugins.git
      path: packages/google_maps_flutter/google_maps_flutter/

然后你可以通过直接在标记上设置来更改图标。 我使用"OnTap"方法来完成这个操作。

Marker marker = Marker(
  icon: firstIcon,
  markerId: MarkerId(id),
  position: position,
  infoWindow: InfoWindow(
    title: name,
    snippet: address,
  ),
  onTap: () {
    setState(() {
      _markers[name]?.icon = secondIcon;
    });
  }
);

整个Marker类:
@immutable
class Marker implements MapsObject {
  /// Creates a set of marker configuration options.
  ///
  /// Default marker options.
  ///
  /// Specifies a marker that
  /// * is fully opaque; [alpha] is 1.0
  /// * uses icon bottom center to indicate map position; [anchor] is (0.5, 1.0)
  /// * has default tap handling; [consumeTapEvents] is false
  /// * is stationary; [draggable] is false
  /// * is drawn against the screen, not the map; [flat] is false
  /// * has a default icon; [icon] is `BitmapDescriptor.defaultMarker`
  /// * anchors the info window at top center; [infoWindowAnchor] is (0.5, 0.0)
  /// * has no info window text; [infoWindowText] is `InfoWindowText.noText`
  /// * is positioned at 0, 0; [position] is `LatLng(0.0, 0.0)`
  /// * has an axis-aligned icon; [rotation] is 0.0
  /// * is visible; [visible] is true
  /// * is placed at the base of the drawing order; [zIndex] is 0.0
  /// * reports [onTap] events
  /// * reports [onDragEnd] events
  Marker({
    required this.markerId,
    this.alpha = 1.0,
    this.anchor = const Offset(0.5, 1.0),
    this.consumeTapEvents = false,
    this.draggable = false,
    this.flat = false,
    this.icon = BitmapDescriptor.defaultMarker,
    this.infoWindow = InfoWindow.noText,
    this.position = const LatLng(0.0, 0.0),
    this.rotation = 0.0,
    this.visible = true,
    this.zIndex = 0.0,
    this.onTap,
    this.onDrag,
    this.onDragStart,
    this.onDragEnd,
  }) : assert(alpha == null || (0.0 <= alpha && alpha <= 1.0));

  /// Uniquely identifies a [Marker].
  final MarkerId markerId;

  @override
  MarkerId get mapsId => markerId;

  /// The opacity of the marker, between 0.0 and 1.0 inclusive.
  ///
  /// 0.0 means fully transparent, 1.0 means fully opaque.
  final double alpha;

  /// The icon image point that will be placed at the [position] of the marker.
  ///
  /// The image point is specified in normalized coordinates: An anchor of
  /// (0.0, 0.0) means the top left corner of the image. An anchor
  /// of (1.0, 1.0) means the bottom right corner of the image.
  final Offset anchor;

  /// True if the marker icon consumes tap events. If not, the map will perform
  /// default tap handling by centering the map on the marker and displaying its
  /// info window.
  final bool consumeTapEvents;

  /// True if the marker is draggable by user touch events.
  final bool draggable;

  /// True if the marker is rendered flatly against the surface of the Earth, so
  /// that it will rotate and tilt along with map camera movements.
  final bool flat;

  /// A description of the bitmap used to draw the marker icon.
  BitmapDescriptor icon;

  /// A Google Maps InfoWindow.
  ///
  /// The window is displayed when the marker is tapped.
  final InfoWindow infoWindow;

  /// Geographical location of the marker.
  final LatLng position;

  /// Rotation of the marker image in degrees clockwise from the [anchor] point.
  final double rotation;

  /// True if the marker is visible.
  final bool visible;

  /// The z-index of the marker, used to determine relative drawing order of
  /// map overlays.
  ///
  /// Overlays are drawn in order of z-index, so that lower values means drawn
  /// earlier, and thus appearing to be closer to the surface of the Earth.
  final double zIndex;

  /// Callbacks to receive tap events for markers placed on this map.
  final VoidCallback? onTap;

  /// Signature reporting the new [LatLng] at the start of a drag event.
  final ValueChanged<LatLng>? onDragStart;

  /// Signature reporting the new [LatLng] at the end of a drag event.
  final ValueChanged<LatLng>? onDragEnd;

  /// Signature reporting the new [LatLng] during the drag event.
  final ValueChanged<LatLng>? onDrag;

  /// Creates a new [Marker] object whose values are the same as this instance,
  /// unless overwritten by the specified parameters.
  Marker copyWith({
    double? alphaParam,
    Offset? anchorParam,
    bool? consumeTapEventsParam,
    bool? draggableParam,
    bool? flatParam,
    BitmapDescriptor? iconParam,
    InfoWindow? infoWindowParam,
    LatLng? positionParam,
    double? rotationParam,
    bool? visibleParam,
    double? zIndexParam,
    VoidCallback? onTapParam,
    ValueChanged<LatLng>? onDragStartParam,
    ValueChanged<LatLng>? onDragParam,
    ValueChanged<LatLng>? onDragEndParam,
  }) {
    return Marker(
      markerId: markerId,
      alpha: alphaParam ?? alpha,
      anchor: anchorParam ?? anchor,
      consumeTapEvents: consumeTapEventsParam ?? consumeTapEvents,
      draggable: draggableParam ?? draggable,
      flat: flatParam ?? flat,
      icon: iconParam ?? icon,
      infoWindow: infoWindowParam ?? infoWindow,
      position: positionParam ?? position,
      rotation: rotationParam ?? rotation,
      visible: visibleParam ?? visible,
      zIndex: zIndexParam ?? zIndex,
      onTap: onTapParam ?? onTap,
      onDragStart: onDragStartParam ?? onDragStart,
      onDrag: onDragParam ?? onDrag,
      onDragEnd: onDragEndParam ?? onDragEnd,
    );
  }

  /// Creates a new [Marker] object whose values are the same as this instance.
  Marker clone() => copyWith();

  /// Converts this object to something serializable in JSON.
  Object toJson() {
    final Map<String, Object> json = <String, Object>{};

    void addIfPresent(String fieldName, Object? value) {
      if (value != null) {
        json[fieldName] = value;
      }
    }

    addIfPresent('markerId', markerId.value);
    addIfPresent('alpha', alpha);
    addIfPresent('anchor', _offsetToJson(anchor));
    addIfPresent('consumeTapEvents', consumeTapEvents);
    addIfPresent('draggable', draggable);
    addIfPresent('flat', flat);
    addIfPresent('icon', icon.toJson());
    addIfPresent('infoWindow', infoWindow._toJson());
    addIfPresent('position', position.toJson());
    addIfPresent('rotation', rotation);
    addIfPresent('visible', visible);
    addIfPresent('zIndex', zIndex);
    return json;
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    if (other.runtimeType != runtimeType) return false;
    final Marker typedOther = other as Marker;
    return markerId == typedOther.markerId &&
        alpha == typedOther.alpha &&
        anchor == typedOther.anchor &&
        consumeTapEvents == typedOther.consumeTapEvents &&
        draggable == typedOther.draggable &&
        flat == typedOther.flat &&
        icon == typedOther.icon &&
        infoWindow == typedOther.infoWindow &&
        position == typedOther.position &&
        rotation == typedOther.rotation &&
        visible == typedOther.visible &&
        zIndex == typedOther.zIndex;
  }

  @override
  int get hashCode => markerId.hashCode;

  @override
  String toString() {
    return 'Marker{markerId: $markerId, alpha: $alpha, anchor: $anchor, '
        'consumeTapEvents: $consumeTapEvents, draggable: $draggable, flat: $flat, '
        'icon: $icon, infoWindow: $infoWindow, position: $position, rotation: $rotation, '
        'visible: $visible, zIndex: $zIndex, onTap: $onTap, onDragStart: $onDragStart, '
        'onDrag: $onDrag, onDragEnd: $onDragEnd}';
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接