美文网首页
高德地图-选择地点开发(小白入门开发地图)

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

作者: 阡陌昏晨 | 来源:发表于2022-03-10 16:34 被阅读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)
    

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

    相关文章

      网友评论

          本文标题:高德地图-选择地点开发(小白入门开发地图)

          本文链接:https://www.haomeiwen.com/subject/trafdrtx.html