如何为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
相关产品推荐
相关产品推荐

