如何将复杂数据传递给 GoogleMap 上的自定义信息窗口

如何将复杂数据传递给 GoogleMap 上的自定义信息窗口

原文:https://medium.com/hackernoon/how-to-pass-complex-data-to-custom-infowindows-on-a-googlemap-3a50d0df1be0

Orb thingy and sky with clouds. Fuck yeah

最差。博客。贴吧。标题。永远不会。

妈的。你刚刚点击了一篇题为“如何将复杂数据传递到 GoogleMap 上的自定义信息窗口”的文章吗?我对你的求知欲印象深刻。

在 Android 上,当你点击 GoogleMap 对象上的一个标记时,就会弹出一个信息窗口。InfoWindow 包含(不出所料)信息,这些信息通常与放置标记的位置相关。这是默认信息窗口的样子(截图来自我的应用, Looxie

看到那个“四级用户:收集 2059 积分”的东西了吗?这就是默认信息窗口的外观。

有时候,那是行不通的。例如,您可能希望在信息窗口上放置一个图像。或者在上面设置一个自定义的字体,这样它就可以和你的应用程序的其他部分保持一致。例如,这是我在我最新的实验应用中想要的信息窗口的样子

看到工作中的甜甜圈字体了吗?可爱的“播放”按钮呢?这需要使用定制的信息窗口。自定义信息窗口并不是本文的重点(而是传递给信息窗口的信息),但是这里有一些步骤,供外行参考

<fragment android:id=”@+id/map”    
 **android:name=”com.google.android.gms.maps.SupportMapFragment”**    android:layout_width=”match_parent” 
    android:layout_height=”match_parent” />
  • 这将允许您在 Java 代码中将转换为 SupportMapFragment ,如下所示
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.map);
  • 最后,通过调用片段上的 getMapAsync()并传入当前活动上下文,在片段中显示地图
mapFragment.getMapAsync(this);

如果您的设置正常,您现在应该会在片段中看到一个 Google 地图。

要开始在 Google 地图上放置和操作标记,让托管地图的活动实现 OnMapReadyCallback 接口总是一个好主意。这将允许您(实际上是强迫您)在活动中实现一个名为 onMapReady() 的回调方法,该方法将在地图加载并准备就绪后立即执行。

public void onMapReady(GoogleMap map) {}

该方法向您传递一个 GoogleMap 实例,然后您可以使用它在地图上执行各种操作。

您现在可以通过执行以下操作在地图上放置一个标记(在 onMapReady() 中)

Marker marker = map.addMarker(new MarkerOptions().position(**latLng**) .icon(BitmapDescriptorFactory.fromResource(**iconResource**)) .title(**title**).snippet(**snippet**));

粗体变量分别是,

  • 一个包含你的纬度和经度的对象
  • 图标资源,如 R.drawable.my_icon
  • 包含标记标题的字符串变量
  • 另一个保存标记额外信息的字符串变量叫做片段。 记住这一条,很重要。

这将在地图上放置一个带有默认信息窗口的标记。然而,众所周知

默认的信息窗口很难看。默认信息窗口正在运行。当默认的信息窗口出现在信息窗口学校时,它们会受到更酷、更个性化的信息窗口的欺负。你想让你的信息窗口被欺负吗,野蛮人?

这是从《当你在谷歌地图上放置标记时会发生什么》一书中直接引用的,所以闭嘴,跟着我做。

要创建自己的定制 InfoWindow,您需要创建自己的实现 GoogleMap 的类。InfoWindowAdapter 然后覆盖两个方法: getInfoContents()getInfoWindow()

这两种方法的区别在于, getInfoContents() 提供了一个默认的“气泡”、阴影和指向标记的脱字符号(见上面我的第一个截图),而 getInfoWindow() 没有提供任何东西,就像 1998 年家庭度假时你的那个吝啬叔叔,当你在游泳池边想要一个奇怪的冰淇淋,但他太便宜了,没有给你买。

[深呼吸]

当您覆盖 getInfoWindow()时,您通过膨胀一个 XML 布局来提供整个布局、背景和所有内容。下面是 InfoWindowAdapter 的一个实现

public class InfoWindowCustom implements GoogleMap.InfoWindowAdapter { Context context; 
    LayoutInflater inflater; public InfoWindowCustom(Context context) {
           this.context = context;
    } @Override    
    public View **getInfoContents(Marker marker)** {        
        return null;    
    } @Override
    public View **getInfoWindow(Marker marker)** { inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);   // **R.layout.echo_info_window** is a layout in my 
   // **res/layout folder**. You can provide your own View v = inflater.inflate(*R.layout.echo_info_window*, null);   

    TextView title = (TextView) v.findViewById(R.id.info_window_title);     
  TextView subtitle = (TextView) v.findViewById(R.id.info_window_subtitle); title.setText(marker.getTitle());
    subtitle.setText(marker.getSnippet()); return v; }}

同时,回到显示地图的活动中的 onMapReady() 的神奇土地,您必须在地图上设置 InfoWindowAdapter 实现,就像这样

map.setInfoWindowAdapter(new InfoWindowCustom(this));

从现在开始,无论何时点击一个标记,所有的标记信息都将被漂亮地显示出来,被你的自定义信息窗口框住。

俄罗斯山上实现的承诺

但是等等!这不是我承诺的!我承诺的是将复杂数据传递给 InfoWindow 适配器的能力,现在这似乎有点困难,因为标记只能携带两部分数据:一个标题和一个片段

当我第一次遇到这个问题时,我的解决方案是将我想要显示的所有内容连接到代码片段中,用换行符(" \n ")分隔代表不同数据的不同行。

然而,这意味着,如果我想对不同的数据片段采用不同的样式,我将不得不修改 Spannables 和 String 的长度。您曾经使用 Spannables 处理过串联的字符串数据吗?我有,而且我很确定撒旦的肛门侵犯是一个更令人兴奋的前景。

没有。我需要更简单的东西。然后突然我的眼睛亮了起来,我觉得自己就像是维尔纳·爱因斯坦发现了马克思主义。

为什么我不能简单地将对象的 JSON 表示传递给代码片段,然后在 InfoWindowAdapter 中检索该代码片段,并将其转换回对象呢?

事实证明我可以。我做到了。

假设您有一个名为 MarkerInfo 的类

public class MarkerInfo { private String title;
    private String subtitle;
    private String soundUrl;
    private int numberOfPlays; public MarkerInfo() { } // getters and setters omitted because I'm not writing this in
   // an IDE. But assume that they are there}

将该类的对象转换成 JSON 表示并转换回对象的一个超级简单的方法是使用像 Gson 这样的库。

在将 MarkerInfo 对象导入到您的项目中之后,您只需这样做就可以将它转换成字符串(JSON)表示

MarkerInfo markerInfo = new MarkerInfo();
markerInfo.setTitle("Shit went down");
markerInfo.setSubtitle("In Hell's Kitchen");
markerInfo.setSoundUrl("https://www.luke.com/matthew/jessica/dumbass.mp3");
markerInfo.setNumberOfPlays(66);Gson gson = new Gson();
**String markerInfoString = gson.toJson(markerInfo);**

因此,当您在标记上设置 snippet 属性时,您可以将结果字符串传递给它,然后在您的自定义 InfoWindowAdapter 类中,您可以检索对象的字符串表示形式,并将其转换回对象。

Gson gson = new Gson();**MarkerInfo aMarkerInfo = gson.fromJson(marker.getSnippet(), MarkerInfo.class);**

现在,您可以单独访问任何对象字段,并在您认为合适的时候在视图上设置它。

很酷吧。当然,在使用正确的关键词在互联网上进行一些研究后,我发现在我“发现”之前,其他人已经使用过这个技巧,但是去他妈的那些家伙,因为他们不是我。


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除