高德地图-选择地点开发(小白入门开发地图)

2022-03-10  本文已影响0人  阡陌昏晨

下图是产品要求实现的在地图上选择地点的需求,类似仆仆小程序上选择位置功能

image.png

1、没有开发经验的第一步需要参考官网
https://lbs.amap.com/api/android-sdk/summary/

2、项目中引入地图sdk 自己可以根据官网修改版本号
//3D地图和导航
implementation 'com.amap.api:navi-3dmap:7.0.0_3dmap7.0.0'
//定位功能
// implementation 'com.amap.api:location:4.7.2'
//搜索功能
implementation 'com.amap.api:search:6.9.2'

3、核心代码 如下

open class MapSelectActivity : BaseTitleActivity() {


    private val TAG = "map"
    private lateinit var mMapView: MapView
    private lateinit var mAmap: AMap
    private lateinit var mRv: RecyclerView
    private lateinit var mRvBottom: RecyclerView
    private lateinit var myLocationStyle: MyLocationStyle
    private lateinit var mEtAddress: EditText
    private lateinit var mTvCancel: TextView
    private lateinit var mIvLocation: ImageView

    private lateinit var middleIcon: BitmapDescriptor

    /**
     * 上面的rv是关键次搜索出来的位置数据
     */
    private lateinit var mAdapter: SelectMapAdapter
    private var mDatas: MutableList<PoiItem> = mutableListOf()

    /**
     * 底部rv是附近的位置
     */
    private lateinit var mBottomAdapter: SelectMapAdapter
    private var mBottomDatas: MutableList<PoiItem> = mutableListOf()

    /**
     * 手动选择的不需要再去监听中心点关键字查询
     */
    private var mIsItemChecked = false

    /**
     * 第一次有经纬度 通过经纬度去关键字查询
     */
    private var mIsFirstLocation = false

    /**
     * 传递过来的经纬度
     */
    private var mLat = 0.0
    private var mLng = 0.0
    private var mAddress = ""
    private var mName = ""

    private val PAGE = 0
    private val PAGE_NUM = 30

    companion object {
        const val LAT = "lat"
        const val LNG = "lng"
        const val NAME = "name"
        const val ADDRESS = "address"
        const val SELECT_MAP_RESULT_CODE = 99

        fun startActivity(
            context: Context,
            lat: Double,
            lng: Double,
            address: String,
            name: String
        ) {
            val intent = Intent(context, MapSelectActivity::class.java)
            intent.putExtra(LAT, lat)
            intent.putExtra(LNG, lng)
            intent.putExtra(ADDRESS, address)
            intent.putExtra(NAME, name)
            (context as Activity).startActivityForResult(intent, SELECT_MAP_RESULT_CODE)
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_map_select)
        mTitleBar.setTitle("选择地点")
        mTitleBar.setRightText(getString(R.string.sure))
        mTitleBar.setRightTextSize(16)
        mTitleBar.setRightTextColor(ContextCompat.getColor(this, R.color.main_color))
        mTitleBar.setRightTextClickListener {
            onSure()
        }

        mMapView = findViewById(R.id.mapView)
        mRv = findViewById(R.id.rv)
        mRvBottom = findViewById(R.id.rv_bottom)
        mEtAddress = findViewById(R.id.et_address)
        mTvCancel = findViewById(R.id.tv_cancel)
        mIvLocation = findViewById(R.id.iv_icon_location)

        middleIcon = BitmapDescriptorFactory.fromResource(R.drawable.map_location)
        mMapView.onCreate(savedInstanceState)
        mAmap = mMapView.map
        initLocationStyle()
        initView()
    }


    private fun initLocationStyle() {
        myLocationStyle =
            MyLocationStyle() //初始化定位蓝点样式类myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE);//连续定位、且将视角移动到地图中心点,定位点依照设备方向旋转,并且会跟随设备移动。(1秒1次定位)如果不设置myLocationType,默认也会执行此种模式。
        //修改默认的定位图片
        myLocationStyle.myLocationIcon(middleIcon)
        //定位一次,且将视角移动到地图中心点
        myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE)
        mAmap.myLocationStyle = myLocationStyle //设置定位蓝点的Style
        //缩放按钮不显示
        mAmap.uiSettings.isZoomControlsEnabled = false
        //定位按钮不显示
        mAmap.uiSettings.isMyLocationButtonEnabled = false
        //图的缩放级别一共分为 17 级,从 3 到 19。数字越大,展示的图面信息越精细。
        mAmap.moveCamera(CameraUpdateFactory.zoomTo(15f))
        //获取经纬度
        mLat = intent.getDoubleExtra(LAT, 0.0)
        mLng = intent.getDoubleExtra(LNG, 0.0)
        mAddress = intent.getStringExtra(ADDRESS)
        mName = intent.getStringExtra(NAME)
        if (mLat > 0 && mLng > 0) {
            //如果有经纬度就使用经纬度作为中心点
            mAmap.isMyLocationEnabled = false
            changeCenterPos(mLat, mLng)
            mIsFirstLocation = true
        } else {
            //开关开启会自动定位当前所在的位置
            mAmap.isMyLocationEnabled = true
        }
        mAmap.setOnCameraChangeListener(object : AMap.OnCameraChangeListener {
            override fun onCameraChange(p0: CameraPosition?) {

            }

            override fun onCameraChangeFinish(pos: CameraPosition?) {
                //如果是item选中后的项目 不需要再次监听
                if (mIsItemChecked) {
                    mIsItemChecked = false
                    return
                }
                val centerX = pos!!.target.latitude
                val centerY = pos!!.target.longitude
                Log.d(TAG, "centerX=" + centerX + "centerY" + centerY)
                if (mIsFirstLocation) {
                    mIsFirstLocation = false
                    poiSearch(mLat, mLng)
                } else {
                    poiSearch(centerX, centerY)
                    //地图移动中心点的方法
                    changeCenterPos(centerX, centerY)
                }

            }

        })


    }

    private fun initView() {
        mAdapter = SelectMapAdapter()
        mRv.layoutManager = LinearLayoutManager(this)
        mRv.adapter = mAdapter


        mBottomAdapter = SelectMapAdapter()
        mRvBottom.layoutManager = LinearLayoutManager(this)
        mRvBottom.adapter = mBottomAdapter

        mEtAddress.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (TextUtils.isEmpty(s)) {
                    showTopRv(false)
                    mTvCancel.visibility = View.GONE
                } else {
                    mDatas.clear()
                    mAdapter.notifyDataSetChanged()
                    mTvCancel.visibility = View.VISIBLE
                }
            }

            override fun afterTextChanged(s: Editable?) {

            }

        })
        mTvCancel.setOnClickListener {
            mEtAddress.setText("")
            mTvCancel.visibility = View.GONE
        }
        mAdapter.setOnItemClickListener(object : OnItemClickListener {
            override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, pos: Int) {
                //点击后去掉之前记录的 重新标志
                mDatas.forEach {
                    it.isIndoorMap = false
                }
                val item = mDatas.get(pos)
                item.isIndoorMap = true
                mAdapter.notifyDataSetChanged()
                showTopRv(false)
//                //滚动指定位置
//                mRvBottom.scrollToPosition(pos)
                //让地图移动到选中的位置 并且不让它再次中心点关键字搜索
                mIsItemChecked = true
                changeCenterPos(item.latLonPoint.latitude, item.latLonPoint.longitude)
                //通过经纬度再去周边搜索
                poiSearch(item.latLonPoint.latitude, item.latLonPoint.longitude)
            }

        })
        mBottomAdapter.setOnItemClickListener(object : OnItemClickListener {
            override fun onItemClick(p0: BaseQuickAdapter<*, *>, view: View, pos: Int) {
                mBottomDatas.forEach {
                    it.isIndoorMap = false
                }
                val item = mBottomDatas.get(pos)
                item.isIndoorMap = true
                mBottomAdapter.notifyDataSetChanged()
                //让地图移动到选中的位置 并且不让它再次中心点关键字搜索
                mIsItemChecked = true
                changeCenterPos(item.latLonPoint.latitude, item.latLonPoint.longitude)
            }

        })
        //搜索按钮
        mEtAddress.setOnEditorActionListener(object : TextView.OnEditorActionListener {
            override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
                if (actionId == EditorInfo.IME_ACTION_DONE ||
                    actionId == EditorInfo.IME_ACTION_SEARCH
                ) {
                    //获取当前定位的城市
                    var cityCode = ""
                    if (!TextUtils.isEmpty(CiasConstant.locationInfoModel.cityCode)) {
                        cityCode = CiasConstant.locationInfoModel.cityCode
                    }
                    keyWordSearch(mEtAddress.text.toString(), cityCode)
                    showTopRv(true)
                    InputManagerUtil.hideKeyboard(mEtAddress)
                    return true
                }
                return false
            }

        })

        mIvLocation.setOnClickListener {
            LocationManager.getInstance().startLocationOnce {
                changeCenterPos(it.latitude, it.longitude)
            }
        }
    }

    /**
     * 2个recycerview只显示一个
     */
    private fun showTopRv(isShow: Boolean) {
        if (isShow) {
            mRv.visibility = View.VISIBLE
            mRvBottom.visibility = View.GONE
        } else {
            mRv.visibility = View.GONE
            mRvBottom.visibility = View.VISIBLE
        }
    }

    private fun changeCenterPos(centerX: Double, centerY: Double) {
        mAmap.clear()
        //改变地图的中心点
        val cameraUpdate = CameraUpdateFactory.newLatLng(LatLng(centerX, centerY))
//        val cameraUpdate = CameraUpdateFactory.newCameraPosition(
//            CameraPosition(
//                LatLng(centerX, centerY),
//                15f,
//                30f,
//                0f
//            )
//        )
        mAmap.moveCamera(cameraUpdate)

        //添加自定义的蓝点icon
        val markerOptions = MarkerOptions()
            .icon(middleIcon)
            .position(LatLng(centerX, centerY))
        val maker = mAmap.addMarker(markerOptions)
        val width = LocalDisplay.getScreenWidth(this) / 2
        val height = LocalDisplay.getScreenHeight(this) / 2 - 80
        maker.setPositionByPixels(width, height)
    }

    private fun keyWordSearch(txt: String, cityCode: String) {
        var query: PoiSearch.Query? = null
        //如果是关键字搜索
        if (!TextUtils.isEmpty(txt)) {
            query = PoiSearch.Query(txt, "", cityCode)
        } else {
            query = PoiSearch.Query("", "", cityCode)
        }
        query.pageSize = PAGE_NUM
        query.pageNum = PAGE
        val poiSearch = PoiSearch(this, query)
        poiSearch.setOnPoiSearchListener(object : PoiSearch.OnPoiSearchListener {

            override fun onPoiSearched(result: PoiResult?, p1: Int) {
                mDatas.clear()
                mDatas.addAll(result?.pois!!)
                mDatas.forEach {
                    it.isIndoorMap = false
                }
                mAdapter.setList(mDatas)
            }

            override fun onPoiItemSearched(p0: PoiItem?, p1: Int) {

            }

        })
        poiSearch.searchPOIAsyn();
    }

    private fun poiSearch(lat: Double, lng: Double) {
        var query: PoiSearch.Query = PoiSearch.Query("", "", "")
        query.pageSize = PAGE_NUM
        query.pageNum = PAGE
        val poiSearch = PoiSearch(this, query)
        if (lat > 0f && lng > 0f) {
            poiSearch.bound = PoiSearch.SearchBound(LatLonPoint(lat, lng), 1000, true)
        }
        poiSearch.setOnPoiSearchListener(object : PoiSearch.OnPoiSearchListener {

            override fun onPoiSearched(result: PoiResult?, p1: Int) {
                mBottomDatas.clear()
                mBottomDatas.addAll(result?.pois!!)
                dataFilterAddSelected()
                mBottomAdapter.setList(mBottomDatas)
            }

            override fun onPoiItemSearched(p0: PoiItem?, p1: Int) {

            }

        })
        poiSearch.searchPOIAsyn();
    }


    /**
     * 对比数据给选中的数据增加被选中的标识
     */
    private fun dataFilterAddSelected() {
        var selectItem: PoiItem? = null
        mBottomDatas.forEach { poiItem ->
            poiItem.isIndoorMap = false
            if (poiItem.latLonPoint.latitude == mLat &&
                poiItem.latLonPoint.longitude == mLng
                && poiItem.snippet.equals(mAddress)
                && poiItem.title.equals(mName)
            ) {
                poiItem.isIndoorMap = true
                selectItem = poiItem
            }
        }
        //没有匹配上就让第一个默认选中
        if (selectItem == null && mBottomDatas.size > 0) {
            mBottomDatas.get(0).isIndoorMap = true
        }
    }

    private fun onSure() {
        var isSelected = false
        mBottomDatas.forEach {
            if (it.isIndoorMap) {
                isSelected = true
                val intent = Intent()
                intent.putExtra(LAT, it.latLonPoint.latitude)
                intent.putExtra(LNG, it.latLonPoint.longitude)
                intent.putExtra(NAME, it.title)
                intent.putExtra(ADDRESS, it.snippet)
                setResult(Activity.RESULT_OK, intent)
                finish()
                return@forEach
            }
        }
        if (!isSelected) {
            ToastUtil.show("您还没有选择地点")
        }
    }

    @Override
    override fun onDestroy() {
        super.onDestroy();
        //在activity执行onDestroy时执行mMapView.onDestroy(),销毁地图
        mMapView.onDestroy();
    }

    override fun onResume() {
        super.onResume()
        //在activity执行onResume时执行mMapView.onResume (),重新绘制加载地图
        mMapView.onResume();
    }


    override fun onPause() {
        super.onPause()
        mMapView.onPause()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        mMapView.onSaveInstanceState(outState)
    }

}

布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.amap.api.maps.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:id="@+id/rl_head"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_40"
        android:layout_marginLeft="@dimen/dp_10"
        android:layout_marginTop="@dimen/dp_10"
        android:layout_marginRight="@dimen/dp_10"
        android:background="@drawable/rect_fffff_6_solid">

        <EditText
            android:id="@+id/et_address"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@null"
            android:drawableLeft="@drawable/ic_search"
            android:drawablePadding="@dimen/dp_4"
            android:gravity="center_vertical"
            android:hint="搜索地点"
            android:imeOptions="actionSearch"
            android:inputType="text"
            android:maxLines="1"
            android:paddingStart="@dimen/dp_6"
            android:paddingEnd="@dimen/dp_6"
            android:textColor="#383838"
            android:textColorHint="#c8c8c8"
            android:textSize="@dimen/sp_16" />

        <TextView
            android:id="@+id/tv_cancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="@dimen/dp_15"
            android:text="@string/cancel"
            android:textColor="@color/main_color"
            android:textSize="@dimen/dp_16"
            android:visibility="gone" />


    </RelativeLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/rl_head"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="@dimen/dp_10"
        android:layout_marginTop="@dimen/dp_4"
        android:layout_marginRight="@dimen/dp_10"
        android:layout_marginBottom="@dimen/dp_16"
        android:background="@color/white"
        android:visibility="gone" />


    <ImageView
        android:id="@+id/iv_icon_location"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/rv_bottom"
        android:layout_alignParentRight="true"
        android:layout_marginRight="@dimen/dp_16"
        android:layout_marginBottom="@dimen/dp_24"
        android:src="@drawable/icon_location" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_bottom"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_180"
        android:layout_alignParentBottom="true"
        android:background="@color/white" />

</RelativeLayout>

总结
1、替换蓝点
//修改默认的定位图片
myLocationStyle.myLocationIcon(middleIcon)
2、一定要设置定位类型 一次定位
myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATE)
3、通过地图拖动获取地图中心点

 mAmap.setOnCameraChangeListener(object : AMap.OnCameraChangeListener {
            override fun onCameraChange(p0: CameraPosition?) {

            }

            override fun onCameraChangeFinish(pos: CameraPosition?) {
                //如果是item选中后的项目 不需要再次监听
                if (mIsItemChecked) {
                    mIsItemChecked = false
                    return
                }
                val centerX = pos!!.target.latitude
                val centerY = pos!!.target.longitude
                Log.d(TAG, "centerX=" + centerX + "centerY" + centerY)
                if (mIsFirstLocation) {
                    mIsFirstLocation = false
                    poiSearch(mLat, mLng)
                } else {
                    poiSearch(centerX, centerY)
                    //地图移动中心点的方法
                    changeCenterPos(centerX, centerY)
                }

            }

        })

4、让中心蓝点固定在屏幕中间

     //添加自定义的蓝点icon
        val markerOptions = MarkerOptions()
            .icon(middleIcon)
            .position(LatLng(centerX, centerY))
        val maker = mAmap.addMarker(markerOptions)
        val width = LocalDisplay.getScreenWidth(this) / 2
        val height = LocalDisplay.getScreenHeight(this) / 2 - 80
        maker.setPositionByPixels(width, height)

基本以上就是开发的难点了 很适合小白入门开发高德地图

上一篇下一篇

猜你喜欢

热点阅读