
image.png

image.png
build.gradle(Moudle.app)依賴
implementation 'com.amap.api:3dmap:latest.integration'
implementation 'com.amap.api:location:latest.integration'
implementation 'com.amap.api:search:latest.integration'
配置
defaultConfig {
applicationId "包名"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
ndk {
//選擇要添加的對(duì)應(yīng)cpu類型的.so庫(kù)。
//熱修復(fù)支持五種
abiFilters 'arm64-v8a', 'armeabi', 'armeabi-v7a'
}
}
androidmanifest配置
<meta-data android:name="com.amap.api.v2.apikey" android:value="高德地圖官網(wǎng)申請(qǐng)"></meta-data>
<service android:name="com.amap.api.location.APSService"></service>
布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="@color/white"
android:layout_width="match_parent" android:layout_height="match_parent">
<include
layout="@layout/activity_left_title_text_view"/>
<FrameLayout
android:layout_margin="@dimen/dp_10"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_33">
<EditText
android:id="@+id/etSearch"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/hui_20_circle_white_shape_bg"
android:drawableLeft="@mipmap/search_hui"
android:drawablePadding="@dimen/dp_6"
android:hint="小區(qū)/寫(xiě)字樓/學(xué)校等"
android:paddingLeft="@dimen/dp_77"
android:singleLine="true"
android:imeOptions="actionSearch"
android:textColorHint="@color/hui_ffc"
android:textSize="@dimen/sp_15" />
<TextView
android:id="@+id/tvCity"
android:drawablePadding="@dimen/dp_5"
android:drawableRight="@mipmap/ic_local"
android:layout_marginLeft="@dimen/dp_10"
android:text="城市"
android:singleLine="true"
android:maxEms="3"
android:ellipsize="end"
android:textSize="@dimen/sp_15"
android:textColor="@color/hui_ff6"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent"/>
<ImageView
android:id="@+id/ivClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center"
android:layout_marginRight="@dimen/dp_15"
android:src="@mipmap/ic_clear"
android:visibility="gone" />
</FrameLayout>
<com.amap.api.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_260" />
<LinearLayout
android:paddingTop="@dimen/dp_17"
android:paddingBottom="@dimen/dp_17"
android:paddingLeft="@dimen/dp_10"
android:paddingRight="@dimen/dp_10"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:textColor="@color/hui_ffb"
android:textSize="@dimen/sp_12"
android:text="當(dāng)前定位"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<RelativeLayout
android:layout_marginTop="@dimen/dp_10"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvLocal"
android:layout_toLeftOf="@+id/tvChoose"
android:layout_alignParentLeft="true"
android:layout_marginRight="@dimen/dp_15"
android:singleLine="true"
android:ellipsize="end"
android:textColor="@color/hui_ff6"
android:textSize="@dimen/sp_17"
android:text="當(dāng)前位置"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tvChoose"
android:layout_alignParentRight="true"
android:textColor="@color/hui_ff8"
android:textSize="@dimen/sp_15"
android:text="使用此地址"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
<TextView
android:layout_marginTop="@dimen/dp_10"
android:id="@+id/tvLocalInfo"
android:layout_toLeftOf="@+id/tvChoose"
android:layout_marginRight="@dimen/dp_80"
android:singleLine="true"
android:ellipsize="end"
android:textColor="@color/hui_ff6"
android:textSize="@dimen/sp_12"
android:text="位置詳情"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<View
android:background="@color/hui_fff6"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_10"/>
<androidx.core.widget.NestedScrollView
android:paddingBottom="@dimen/dp_10"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvMapList"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.core.widget.NestedScrollView>
</LinearLayout>
activity實(shí)現(xiàn)代碼:
import android.graphics.Color
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import com.amap.api.location.AMapLocation
import com.amap.api.location.AMapLocationClient
import com.amap.api.location.AMapLocationClientOption
import com.amap.api.location.AMapLocationListener
import com.amap.api.maps.AMap
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.LocationSource
import com.amap.api.maps.model.*
import com.amap.api.maps.model.animation.Animation
import com.amap.api.maps.model.animation.TranslateAnimation
import com.amap.api.services.core.AMapException
import com.amap.api.services.core.LatLonPoint
import com.amap.api.services.core.PoiItem
import com.amap.api.services.poisearch.PoiResult
import com.amap.api.services.poisearch.PoiSearch
import com.dsy.jxih.R
import com.dsy.jxih.adapter.PositionAdapter
import com.dsy.jxih.base.BaseActivity
import com.dsy.jxih.tools.PublicTools
import kotlinx.android.synthetic.main.activity_left_title_text_view.*
import kotlinx.android.synthetic.main.activity_map_choose_addr_view.*
import org.jetbrains.anko.toast
/**
*@Created by wrs on 2020/9/18,16:45
*@packageName: com.dsy.jxih.activity
*@Description: 地圖定位選點(diǎn)
*/
class MapChooseAddrActivity : BaseActivity(),View.OnClickListener, LocationSource,
AMapLocationListener, AMap.OnMapLoadedListener, AMap.OnCameraChangeListener,
PoiSearch.OnPoiSearchListener,TextView.OnEditorActionListener {
var aMap: AMap? = null
var mySelfLocationStyle: MyLocationStyle? = null
var mListener: LocationSource.OnLocationChangedListener? = null
var mlocationClient: AMapLocationClient? = null
var mLocationOption: AMapLocationClientOption? = null
var screenMarker: Marker? = null
var latLon: LatLng? = null
var choosePosition = 0
//poi附近搜索// Poi查詢條件類
var query: PoiSearch.Query? = null
var poiSearch: PoiSearch? = null
var keyWord = ""
var lat = 0.0
var lon = 0.0
var positionAdtapter: PositionAdapter? = null
var listPosition = ArrayList<PoiItem>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map_choose_addr_view)
mapView.onCreate(savedInstanceState);// 此方法必須重寫(xiě)
initView()
initMap()
initActLocation()
initPoi()
initData()
initListener()
}
override fun initView() {
tvTitle.text = "所在區(qū)域"
}
fun initMap() {
aMap = mapView.getMap()
mySelfLocationStyle =
MyLocationStyle().apply {
interval(2000) //設(shè)置連續(xù)定位模式下的定位間隔,只在連續(xù)定位模式下生效,單次定位模式下不會(huì)生效。單位為毫秒。
myLocationType(MyLocationStyle.LOCATION_TYPE_FOLLOW_NO_CENTER);//連續(xù)定位、且將視角移動(dòng)到地圖中心點(diǎn),定位藍(lán)點(diǎn)跟隨設(shè)備移動(dòng)。(1秒1次定位)
}
mySelfLocationStyle?.strokeColor(Color.TRANSPARENT)
mySelfLocationStyle?.radiusFillColor(Color.argb(0, 0, 0, 0))
mySelfLocationStyle?.strokeWidth(1.0f)
with(aMap!!) {
isTrafficEnabled = true;// 顯示實(shí)時(shí)交通狀況
setMapType(AMap.MAP_TYPE_NORMAL);// 衛(wèi)星地圖模式MAP_TYPE_SATELLITE
myLocationStyle = mySelfLocationStyle //設(shè)置定位藍(lán)點(diǎn)的Style
isMyLocationEnabled = true // 設(shè)置為true表示啟動(dòng)顯示定位藍(lán)點(diǎn),false表示隱藏定位藍(lán)點(diǎn)并不進(jìn)行定位,默認(rèn)是false。
// minZoomLevel = 16f //設(shè)置顯示比例
moveCamera(CameraUpdateFactory.zoomTo(16f)) //設(shè)置顯示比例 要與上面的一個(gè)設(shè)置聯(lián)合使用才會(huì)起效果
setLocationSource(this@MapChooseAddrActivity)// 設(shè)置定位監(jiān)聽(tīng)
setMyLocationEnabled(true) // 設(shè)置為true表示顯示定位層并可觸發(fā)定位,false表示隱藏定位層并不可觸發(fā)定位,默認(rèn)是false
setMyLocationType(AMap.LOCATION_TYPE_LOCATE)// 設(shè)置定位的類型為定位模式,有定位、跟隨或地圖根據(jù)面向方向旋轉(zhuǎn)幾種
setOnMapLoadedListener(this@MapChooseAddrActivity)//監(jiān)聽(tīng)地圖是否加載完
setOnCameraChangeListener(this@MapChooseAddrActivity)//設(shè)置可視范圍變化時(shí)的回調(diào)的接口方法
}
aMap?.let {
it.getUiSettings().apply {
isMyLocationButtonEnabled = true//設(shè)置默認(rèn)定位按鈕是否顯示,非必需設(shè)置。
isScaleControlsEnabled = true //顯示比列尺
isCompassEnabled = false //指藍(lán)針
isZoomControlsEnabled = true //返回縮放按鈕是否可見(jiàn)
}
}
}
override fun initData() {
positionAdtapter = PositionAdapter(this,listPosition)
val lm = LinearLayoutManager(this)
lm.orientation = LinearLayoutManager.VERTICAL
with(rvMapList){
layoutManager = lm
adapter = positionAdtapter
}
}
//地圖是否加載完監(jiān)聽(tīng)事件
override fun onMapLoaded() {
addMarkerInScreenCenter()
}
//在地圖狀態(tài)改變完成時(shí)回調(diào)此方法。
override fun onCameraChangeFinish(position: CameraPosition?) {
//屏幕中心的Marker跳動(dòng)
startJumpAnimation()
lon = position?.target?.longitude ?: 0.0
lat = position?.target?.latitude ?: 0.0
Log.e("經(jīng)緯度", "======經(jīng)度======:" + lon)
Log.e("經(jīng)緯度", "======維度======:" + lat)
initPoi()
}
override fun onCameraChange(position: CameraPosition?) {
}
/**
* 屏幕中心marker 跳動(dòng)
*/
fun startJumpAnimation() {
if (screenMarker != null && aMap != null) { //根據(jù)屏幕距離計(jì)算需要移動(dòng)的目標(biāo)點(diǎn)
val latLng = screenMarker?.position
val point = aMap!!.projection.toScreenLocation(latLng)
point.y -= PublicTools.tools.dip2px(this, 125f)
val target = aMap?.projection?.fromScreenLocation(point)
//使用TranslateAnimation,填寫(xiě)一個(gè)需要移動(dòng)的目標(biāo)點(diǎn)
val animation: Animation = TranslateAnimation(target)
animation.setInterpolator { input ->
// 模擬重加速度的interpolator
if (input <= 0.5) {
(0.5f - 2 * (0.5 - input) * (0.5 - input)).toFloat()
} else {
(0.5f - Math.sqrt((input - 0.5f) * (1.5f - input).toDouble())).toFloat()
}
}
//整個(gè)移動(dòng)所需要的時(shí)間
animation.setDuration(600)
//設(shè)置動(dòng)畫(huà)
screenMarker?.setAnimation(animation)
//開(kāi)始動(dòng)畫(huà)
screenMarker?.startAnimation()
} else {
Log.e("amap", "screenMarker is null")
}
}
/**
* 在屏幕中心添加一個(gè)Marker
*/
private fun addMarkerInScreenCenter() {
val latLng = aMap!!.cameraPosition.target
val screenPosition = aMap!!.projection.toScreenLocation(latLng)
screenMarker = aMap!!.addMarker(
MarkerOptions()
.anchor(0.5f, 0.5f)
.icon(BitmapDescriptorFactory.fromResource(R.mipmap.purple_pin))
)
//設(shè)置Marker在屏幕上,不跟隨地圖移動(dòng)
screenMarker?.setPositionByPixels(screenPosition.x, screenPosition.y)
}
fun initActLocation() {
if (mlocationClient == null) { //初始化定位
//初始化定位參數(shù)
mLocationOption = AMapLocationClientOption().apply {
locationMode = AMapLocationClientOption.AMapLocationMode.Hight_Accuracy//設(shè)置為高精度定位模式
}
mlocationClient = AMapLocationClient(this)
//設(shè)置定位回調(diào)監(jiān)聽(tīng)
mlocationClient?.setLocationListener(this)
//設(shè)置定位參數(shù)
mlocationClient?.setLocationOption(mLocationOption)
mlocationClient?.startLocation() //啟動(dòng)定位
}
}
override fun deactivate() {
if (mlocationClient != null) {
mlocationClient?.stopLocation();
mlocationClient?.onDestroy();
}
mlocationClient = null;
}
override fun activate(listener: LocationSource.OnLocationChangedListener?) {
mListener = listener;
if (mlocationClient != null) {
mlocationClient?.stopLocation();
mlocationClient?.onDestroy();
}
mlocationClient = null;
}
override fun onLocationChanged(amapLocation: AMapLocation?) {
if (mListener != null && amapLocation != null) {
if (amapLocation != null
&& amapLocation.errorCode === 0
) {
mListener?.onLocationChanged(amapLocation) // 顯示系統(tǒng)小藍(lán)點(diǎn)
mlocationClient?.stopLocation()
tvCity.text = amapLocation.city
tvLocal.text = amapLocation.aoiName
tvLocalInfo.text = amapLocation.address
// province city district
lon = amapLocation.longitude
lat = amapLocation.latitude
choosePosition = 0
latLon = LatLng(lat, lon)
initPoi()
} else {
val errText =
"定位失敗," + amapLocation.errorCode.toString() + ": " + amapLocation.errorInfo
Log.e("AmapErr", errText)
}
}
}
/**
* 初始化搜索
*/
fun initPoi() {
// 第一個(gè)參數(shù)表示搜索字符串,第二個(gè)參數(shù)表示poi搜索類型,第三個(gè)參數(shù)表示poi搜索區(qū)域(空字符串代表全國(guó))
query = PoiSearch.Query(keyWord, null, null)
query?.pageSize = 30 // 設(shè)置每頁(yè)最多返回多少條poiitem
query?.pageNum = 0 // 設(shè)置查第一頁(yè)
query?.extensions=PoiSearch.EXTENSIONS_ALL //每次搜索都返回省市縣信息
poiSearch = PoiSearch(this, query)
poiSearch?.setOnPoiSearchListener(this)
if (TextUtils.isEmpty(keyWord)){//搜索內(nèi)容為空是,按照經(jīng)緯度來(lái)查詢附近地名
poiSearch?.setBound(PoiSearch.SearchBound(LatLonPoint(lat, lon), 0,true)) //根據(jù)設(shè)置的經(jīng)緯度來(lái)查
}else{//模糊搜索時(shí)使用一下配置
poiSearch?.bound = null
}
// 設(shè)置搜索區(qū)域?yàn)橐詌p點(diǎn)為圓心,其周圍5000米范圍
poiSearch?.searchPOIAsyn() // 異步搜索
}
override fun onPoiItemSearched(p0: PoiItem?, rcode: Int) {
}
override fun onPoiSearched(result: PoiResult?, rcode: Int) {
if (rcode == AMapException.CODE_AMAP_SUCCESS) {
if (result?.query == query) {// 是否是同一條
var poiItems = result?.pois
if (null != poiItems && poiItems!!.size > 0) {
Log.e("結(jié)果", "搜索到附近地名了")
listPosition.clear()
// positionAdtapter?.setChoosePosition(choosePosition)
listPosition.addAll(poiItems)
positionAdtapter?.notifyDataSetChanged()
} else {
toast("請(qǐng)稍后")
}
}
} else {
toast("" + rcode)
}
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
if (null != mlocationClient) {
mlocationClient?.onDestroy()
}
listPosition?.let {
it.clear()
null
}
}
/**
* 方法必須重寫(xiě)
*/
override fun onResume() {
super.onResume()
mapView?.onResume()
}
/**
* 方法必須重寫(xiě)
*/
override fun onPause() {
super.onPause()
mapView?.onPause()
}
override fun initListener() {
tvChoose.setOnClickListener(this)
ivBack.setOnClickListener(this)
etSearch.setOnEditorActionListener(this)
}
override fun onClick(v: View?) {
when(v?.id){
R.id.ivBack ->{//返回
finish()
}
R.id.tvChoose ->{//選擇當(dāng)前定位
toast("選擇當(dāng)前定位")
}
}
}
override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
if (actionId == EditorInfo.IME_ACTION_SEARCH){
val searchStr = etSearch.editableText.toString().trim()
if (TextUtils.isEmpty(searchStr)){
keyWord = ""
}else{
val imm = getSystemService(INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.hideSoftInputFromWindow(v?.getWindowToken(), 0)
keyWord = searchStr
initPoi()
}
return false
}
return true
}
}
adapter適配器
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.amap.api.services.core.PoiItem
import com.dsy.jxih.R
import com.dsy.jxih.iml.onAdapterAnyListener
class PositionAdapter(var context: Context,var listData:ArrayList<PoiItem>) : RecyclerView.Adapter<PositionAdapter.ViewHolder>() {
private var listener: onAdapterAnyListener? = null
fun setAdapterClickListener(listener: onAdapterAnyListener) {
this.listener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(context).inflate(R.layout.adapter_map_choose_item_view,parent,false)
return ViewHolder(view)
}
override fun getItemCount(): Int {
return listData.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
with(holder){
val bean = listData.get(position)
tvAddr?.text = bean.title
tvAddrInfo?.text = bean.snippet
}
}
class ViewHolder(view: View) :RecyclerView.ViewHolder(view){
var tvAddr:TextView? = null
var tvAddrInfo:TextView? = null
init {
tvAddr = view.findViewById(R.id.tvAddr)
tvAddrInfo = view.findViewById(R.id.tvAddrInfo)
}
}
}
adapter適配器的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/llLay"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_15"
android:orientation="vertical"
android:paddingLeft="@dimen/dp_10"
android:paddingRight="@dimen/dp_10">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvAddr"
android:layout_alignParentLeft="true"
android:layout_marginRight="@dimen/dp_15"
android:layout_toLeftOf="@+id/ivLocal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:text="北海國(guó)際仲裁院"
android:textColor="@color/hui_ff"
android:textSize="@dimen/sp_17" />
<ImageView
android:id="@+id/ivLocal"
android:layout_width="@dimen/dp_20"
android:layout_height="@dimen/dp_20"
android:layout_alignParentRight="true"
android:adjustViewBounds="true"
android:src="@mipmap/ic_map" />
</RelativeLayout>
<TextView
android:id="@+id/tvAddrInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_80"
android:layout_toLeftOf="@+id/tvChoose"
android:ellipsize="end"
android:singleLine="true"
android:text="深圳市寶安區(qū)寶安中心前海灣卓越時(shí)代廣場(chǎng)…"
android:textColor="@color/hui_ff6"
android:textSize="@dimen/sp_12" />
</LinearLayout>
有需要的碼農(nóng)可以直接拿去使用