目录

  • 地图APP开发日志 Day 2
  • 室内地图显示及楼层控制
  • 自定义楼层控件
  • 选点信息展示
  • 注意


地图APP开发日志 Day 2

  1. 室内地图显示及楼层控制
  2. 选点信息展示

室内地图显示及楼层控制

首先需要介绍原有SDK中的室内地图显示和楼层控制

// 显示室内地图,默认为false
amap.showIndoorMap(true)

// 当显示室内地图时显示楼层控件
amap.uiSettings.isIndoorSwitchEnabled = true

通过上方两行代码确实可以实现室内地图和楼层控制,但是在Day 1中隐藏了高德地图的logo,但是楼层控制控件是跟着logo的位置走的,可以看到下方图中控件始终在logo上方。如果隐藏了logo也就没有了楼层控件了。同时有点报看,那只能自己实现。

ELK分析日志利用高德地图显示IP地理位置_控件


这时就需要使用到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))
                }
            }
        }
    }
}

具体的实现效果如下图,按照西单的层数并没有超过屏幕,所以没有适配滑动

ELK分析日志利用高德地图显示IP地理位置_kotlin_02


注册了onFloorChangeListener接口后即可显示室内地图的不同楼层

选点信息展示

这个功能实现需要先知道手指按下的坐标,通过逆地理编码解析出对应位置。
因为地图中包含很多的地点图标,点击到这些图标上时是无法触发地图点击事件的,所以需要添加AMap.OnMapLongClickListenerAMap.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和与定位点的连线,显示该信息时也同时隐藏了搜索框和控制按钮。

ELK分析日志利用高德地图显示IP地理位置_kotlin_03

注意

  • 使用自定义Marker时,无法使用xml格式的图片
  • 自定义室内地图楼层控件时,应对OnIndoorBuilding方法添加防抖
  • 使用CoordinatorLayout控制视图时,应保证含有layout_behavior的视图应在最外层,防止失效