下图是产品要求实现的在地图上选择地点的需求,类似仆仆小程序上选择位置功能
image.png1、没有开发经验的第一步需要参考官网
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)
基本以上就是开发的难点了 很适合小白入门开发高德地图
网友评论