目录
- 地图APP开发日志 Day 2
- 室内地图显示及楼层控制
- 自定义楼层控件
- 选点信息展示
- 注意
地图APP开发日志 Day 2
- 室内地图显示及楼层控制
- 选点信息展示
室内地图显示及楼层控制
首先需要介绍原有SDK中的室内地图显示和楼层控制
// 显示室内地图,默认为false
amap.showIndoorMap(true)
// 当显示室内地图时显示楼层控件
amap.uiSettings.isIndoorSwitchEnabled = true
通过上方两行代码确实可以实现室内地图和楼层控制,但是在Day 1中隐藏了高德地图的logo,但是楼层控制控件是跟着logo的位置走的,可以看到下方图中控件始终在logo上方。如果隐藏了logo也就没有了楼层控件了。同时有点报看,那只能自己实现。
这时就需要使用到AMap.OnIndoorBuildingActiveListener
接口,并通过setIndoorBuildingInfo(IndoorBuildingInfo indoorBuildingInfo)
切换室内楼层
amap.setIndoorBuildingInfo(info)
override fun OnIndoorBuilding(p0: IndoorBuildingInfo?) {
// 日志输出
p0?.let { info ->
"当前楼层${info.activeFloorIndex} ${info.activeFloorName}, 总楼层${Arrays.toString(info.floor_indexs)} ${Arrays.toString(info.floor_names)}".d()
}
// 参数传值
binding.fcvMain.update(p0)
}
在该回调内打印log来看,p0的参数会发生一定的抖动,通过日志打印p0是否为空,可以看到942
时已经显示了室内地图并返回了p0,当触发手势放大地图时,042
返回了p0为空067
又返回了p0存在,那么在楼层控件中要对该情况进行优化
2022-07-23 15:43:05.942 14670-14670/top.coolcha.map D/MainActivity:OnIndoorBuilding@159: false
2022-07-23 15:43:06.042 14670-14670/top.coolcha.map D/MainActivity:OnIndoorBuilding@159: true
2022-07-23 15:43:06.067 14670-14670/top.coolcha.map D/MainActivity:OnIndoorBuilding@159: false
自定义楼层控件
<!-- 这里高度宽度全部自适应,这样可以无需控制该控件的显隐 -->
<top.coolcha.map.custom.FloorControllerView
android:id="@+id/fcv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
class FloorControllerView(context: Context, attributeSet: AttributeSet) :
LinearLayout(context, attributeSet) {
/**
* 所有楼层
*/
private var floorIndexes: IntArray? = null
private var floorNames: Array<String>? = null
/**
* 当前楼层
*/
private var activeIndex: Int? = null
private var activeName: String? = null
/**
* 当前室内地图唯一id
*/
private var id: String? = null
/**
* 视图列表
*/
private val viewList = mutableListOf<TextView>()
/**
* 楼层信息
*/
private var info: IndoorBuildingInfo? = null
/**
* 点击回调
*/
var onFloorChangeListener: ((IndoorBuildingInfo) -> Unit)? = null
init {
setBackgroundResource(R.drawable.shape_background_radius)
orientation = VERTICAL
}
fun update(info : IndoorBuildingInfo?) {
if (info == null) {
this.info = null
this.id = null
// 如果为空则在100毫秒后判断是否仍为空,防止画面抖动
postDelayed({
if (this.info == null) {
"室内地图信息为空,清空楼层".e()
removeAllViews()
viewList.clear()
}
}, 100)
return
}
if (id != null && info.poiid == id) {
this.activeIndex = info.activeFloorIndex
this.activeName = info.activeFloorName
"相同地图切换,$activeIndex $activeName".d()
updateView()
return
}
this.info = info
this.id = info.poiid
this.activeIndex = info.activeFloorIndex
this.activeName = info.activeFloorName
this.floorIndexes = info.floor_indexs
this.floorNames = info.floor_names
removeAllViews()
this.floorNames?.let {
val size = it.size
// 这里需要反序添加,不然高楼层在最下方
for (i in 0 until size) {
addView(it[size - i - 1])
}
}
}
/**
* 添加楼层信息
* @param name String
*/
private fun addView(name: String) {
val view = TextView(context).apply {
text = name
height = 100
width = 100
gravity = Gravity.CENTER
if (text == activeName) {
setBackgroundResource(R.drawable.shape_floor_active)
setTextColor(resources.getColor(R.color.textColorBack, null))
} else {
setBackgroundColor(Color.WHITE)
setTextColor(resources.getColor(R.color.textColor, null))
}
setOnClickListener {
onFloorChangeListener?.let {
val index = this@FloorControllerView.floorNames?.indexOf(name) ?: 0
info?.let { result ->
result.activeFloorName = name
result.activeFloorIndex = this@FloorControllerView.floorIndexes?.get(index) ?: 0
it.invoke(result)
}
}
}
}
viewList.add(view)
addView(view)
}
/**
* 更新所选楼层
*/
private fun updateView() {
for (view in viewList) {
view.apply {
if (text == activeName) {
setBackgroundResource(R.drawable.shape_floor_active)
setTextColor(resources.getColor(R.color.textColorBack, null))
} else {
setBackgroundColor(Color.WHITE)
setTextColor(resources.getColor(R.color.textColor, null))
}
}
}
}
}
具体的实现效果如下图,按照西单的层数并没有超过屏幕,所以没有适配滑动
注册了onFloorChangeListener
接口后即可显示室内地图的不同楼层
选点信息展示
这个功能实现需要先知道手指按下的坐标,通过逆地理编码解析出对应位置。
因为地图中包含很多的地点图标,点击到这些图标上时是无法触发地图点击事件的,所以需要添加AMap.OnMapLongClickListener
和AMap.OnPOIClickListener
回调
/**
* 地图被点击
* @param p0 LatLng
*/
override fun onMapLongClick(p0: LatLng?) {
p0?.let { latlng ->
"地图点击 ${latlng.latitude}, ${latlng.longitude}".d()
addInfoResult(latlng)
val geocodeSearch = GeocodeSearch(this)
val query = RegeocodeQuery(LatLonPoint(latlng.latitude, latlng.longitude), 50f, GeocodeSearch.AMAP)
query.extensions = "all"
geocodeSearch.getFromLocationAsyn(query)
geocodeSearch.setOnGeocodeSearchListener(object : GeocodeSearch.OnGeocodeSearchListener {
override fun onRegeocodeSearched(p0: RegeocodeResult?, p1: Int) {
// 解析result获取地址描述信息
if (p1 != 1000) {
"逆地理编码操作失败".e()
toast("逆地理编码操作失败")
removeInfoResult()
binding.ivMainInfoClose.performClick()
return
}
p0?.let { result ->
val pois = result.regeocodeAddress.pois
if (pois.size == 0) {
"无POI数据".e()
toast("无POI数据")
removeInfoResult()
binding.ivMainInfoClose.performClick()
return
}
val item = pois[0]
"地图点击 ${item.title}, ${item.snippet}, ${item.typeDes}".d()
addMapResult(item)
}
}
override fun onGeocodeSearched(p0: GeocodeResult?, p1: Int) {
}
})
}
}
/**
* 地图中poi点击
* @param p0 Poi
*/
override fun onPOIClick(p0: Poi?) {
p0?.let { poi ->
val latlng = poi.coordinate
"Poi点击 ${latlng.latitude}, ${latlng.longitude}".d()
"Poi点击 ${poi.name}".d()
addInfoResult(latlng)
val poiSearch = PoiSearch(this, null)
poiSearch.searchPOIIdAsyn(poi.poiId)
poiSearch.setOnPoiSearchListener(object : PoiSearch.OnPoiSearchListener {
override fun onPoiSearched(p0: PoiResult?, p1: Int) {
}
override fun onPoiItemSearched(p0: PoiItem?, p1: Int) {
// 获取PoiItem获取POI的详细信息
if (p1 != 1000) {
"poi搜索失败".e()
toast("POI搜索失败")
removeInfoResult()
binding.ivMainInfoClose.performClick()
return
}
p0?.let { item ->
"poi搜索 ${item.title}, ${item.snippet}, ${item.typeDes}".d()
addMapResult(item)
}
}
})
}
}
下图就是地图选点和POI点击的信息展示,同时添加了Marker和与定位点的连线,显示该信息时也同时隐藏了搜索框和控制按钮。
注意
- 使用自定义Marker时,无法使用xml格式的图片
- 自定义室内地图楼层控件时,应对
OnIndoorBuilding
方法添加防抖 - 使用
CoordinatorLayout
控制视图时,应保证含有layout_behavior
的视图应在最外层,防止失效