You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为osmdroid Polyline创建自定义InfoWindow并显示于线段中点

解决osmdroid Polyline中点显示自定义文本InfoWindow的问题

问题背景

尝试为osmdroid的Polyline创建一个仅含文本、显示在线段中点的自定义InfoWindow,已编写MyInfoWindow类和对应的布局文件,但点击线段后无法看到文本,仅能看到线段本身。

现有代码

MyInfoWindow类(Kotlin)

class MyInfoWindow(layoutResId : Int, map : MapView): InfoWindow(layoutResId, map) {
    init{
        if(titleId == RES_ID){
            setResId(map.context)
        }
        mView.setOnTouchListener(object : OnTouchListener{
            override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
                if(p1!!.action == MotionEvent.ACTION_UP){
                    close()
                }
                return true
            }

        })
    }
    override fun onOpen(item: Any?) {
        val overlay : OverlayWithIW = item as OverlayWithIW
        val title : String = overlay.getTitle()
        if(mView == null){
            return
        }
        val temp : TextView = mView.findViewById(titleId)
        temp.text = title
    }

    override fun onClose() {

    }

    companion object{
        private const val RES_ID : Int = 0
        var titleId : Int = RES_ID
        fun setResId(context : Context){
            titleId = context.resources.getIdentifier("id/poly_title", null, context.packageName)
            Log.i("title", "$titleId")
        }
    }
}

布局文件polyline_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="65dp"
    android:layout_height="65dp"
    android:orientation="vertical"
    android:visibility="gone">
    <TextView
        android:id="@+id/poly_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:maxEms="17"
        android:layout_gravity="left"
        android:text="text"/>
</LinearLayout>

问题分析与修复步骤

1. 修复布局可见性问题

布局根容器默认设置了android:visibility="gone",这会导致InfoWindow默认隐藏,即使代码设置了文本也无法显示。

修复方案:

  • 直接修改布局文件,将android:visibility="gone"改为android:visibility="visible";
  • 或者在onOpen方法中手动设置可见性:
override fun onOpen(item: Any?) {
    // ...原有代码
    mView.visibility = View.VISIBLE
    // ...原有代码
}

2. 修复TextView ID获取错误

setResId方法中,getIdentifier的参数格式错误,正确的参数应该是(资源名称, 资源类型, 包名),原代码传入的"id/poly_title"会导致无法正确找到TextView的ID。

修复方案:
修改setResId方法:

fun setResId(context : Context){
    titleId = context.resources.getIdentifier("poly_title", "id", context.packageName)
    Log.i("title", "$titleId")
}

3. 手动定位InfoWindow到Polyline中点

osmdroid的InfoWindow默认会显示在点击的位置,而不是Polyline的中点,需要手动计算线段中点并调整InfoWindow的位置。

修复方案:
修改onOpen方法,强转item为Polyline,计算中点坐标并设置InfoWindow位置:

override fun onOpen(item: Any?) {
    val polyline = item as? Polyline ?: return
    val title = polyline.title ?: return
    if (mView == null) return

    // 设置视图可见
    mView.visibility = View.VISIBLE
    val temp: TextView = mView.findViewById(titleId)
    temp.text = title

    // 计算Polyline的中点坐标
    val points = polyline.points
    if (points.size >= 2) {
        val midLat = (points.first().latitude + points.last().latitude) / 2.0
        val midLon = (points.first().longitude + points.last().longitude) / 2.0
        val midPoint = GeoPoint(midLat, midLon)
        // 将InfoWindow定位到中点
        this.position = midPoint
        // 可选:让地图聚焦到中点
        mapView.controller.animateTo(midPoint)
    }
}

4. 确保Polyline的基础设置正确

在创建Polyline时,必须确保以下设置:

// 创建Polyline实例
val polyline = Polyline(mapView)
// 设置标题(用于InfoWindow显示)
polyline.title = "线段标题"
// 关联自定义InfoWindow
polyline.infoWindow = MyInfoWindow(R.layout.polyline_layout, mapView)
// 设置可点击
polyline.isClickable = true
// 添加到地图Overlay集合
mapView.overlays.add(polyline)

完整修复后的MyInfoWindow代码

import android.content.Context
import android.view.MotionEvent
import android.view.View
import android.view.View.OnTouchListener
import android.widget.TextView
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.Polyline
import org.osmdroid.views.overlay.infowindow.InfoWindow
import org.osmdroid.util.GeoPoint
import android.util.Log

class MyInfoWindow(layoutResId : Int, map : MapView): InfoWindow(layoutResId, map) {
    init{
        if(titleId == RES_ID){
            setResId(map.context)
        }
        mView.setOnTouchListener(object : OnTouchListener{
            override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
                if(p1?.action == MotionEvent.ACTION_UP){
                    close()
                }
                return true
            }
        })
    }

    override fun onOpen(item: Any?) {
        val polyline = item as? Polyline ?: return
        val title = polyline.title ?: return
        if (mView == null) return

        // 设置视图可见
        mView.visibility = View.VISIBLE
        val temp: TextView = mView.findViewById(titleId)
        temp.text = title

        // 计算Polyline中点并定位InfoWindow
        val points = polyline.points
        if (points.size >= 2) {
            val midLat = (points.first().latitude + points.last().latitude) / 2.0
            val midLon = (points.first().longitude + points.last().longitude) / 2.0
            val midPoint = GeoPoint(midLat, midLon)
            this.position = midPoint
            mapView.controller.animateTo(midPoint)
        }
    }

    override fun onClose() {
        // 可选:关闭时隐藏视图
        mView?.visibility = View.GONE
    }

    companion object{
        private const val RES_ID : Int = 0
        var titleId : Int = RES_ID
        fun setResId(context : Context){
            titleId = context.resources.getIdentifier("poly_title", "id", context.packageName)
            Log.i("title", "$titleId")
        }
    }
}

内容的提问来源于stack exchange,提问作者Roberto Negri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:34:59