diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index da8d67c..037fd9b 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -13,6 +13,7 @@ const val PERMISSIONS_CODE = 999 const val PAGE_LIMIT = 20 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val DISTANCE = 5 //两点间距离阈值,单位:米 val HOME_ICONS = arrayOf( R.drawable.ic_home_map, R.drawable.ic_home_record, R.drawable.ic_home_statistics, diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index da8d67c..037fd9b 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -13,6 +13,7 @@ const val PERMISSIONS_CODE = 999 const val PAGE_LIMIT = 20 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val DISTANCE = 5 //两点间距离阈值,单位:米 val HOME_ICONS = arrayOf( R.drawable.ic_home_map, R.drawable.ic_home_record, R.drawable.ic_home_statistics, diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt index 1dea700..8401ec5 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt @@ -1,22 +1,52 @@ package com.casic.qd.smartwell.view +import android.graphics.Point +import android.location.Location import android.os.Bundle +import android.util.Log import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.* import com.casic.qd.smartwell.R import com.casic.qd.smartwell.base.BaseActivity +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toJson +import com.casic.qd.smartwell.utils.Constant +import com.casic.qd.smartwell.utils.SaveKeyValues +import com.casic.qd.smartwell.widgets.GaoDeClusterMarkerView +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import kotlinx.android.synthetic.main.activity_map.* import kotlinx.android.synthetic.main.include_base_title.* /** * @author a203 * @description 地图页面 - * @package com.casic.qd.smartwell.view * @date 2022/2/17 14:33 * @email 290677893@qq.com */ -class MapActivity : BaseActivity() { +class MapActivity : BaseActivity(), AMap.OnMapLoadedListener, AMap.OnMyLocationChangeListener, + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.OnInfoWindowClickListener { - private var aMap: AMap? = null + private val kTag = "MapActivity" + private var authenticatedType: MutableList = ArrayList() + private lateinit var aMap: AMap + + /** + * 定位点经纬度 + * */ + private lateinit var location: LatLng + + /** + * 所有的marker + */ + private var allMarkerOptions: MutableList = ArrayList() + + /** + * 视野内的marker + */ + private var markerOptionsInView: MutableList = ArrayList() override fun initLayoutView(): Int = R.layout.activity_map @@ -26,20 +56,136 @@ } override fun initData() { - if (aMap == null) { - aMap = mapView.map + val userDeviceJson = SaveKeyValues.getValue(Constant.USER_DEVICE_TYPE, "") as String + if (userDeviceJson.isNotBlank()) { + authenticatedType = Gson().fromJson( + userDeviceJson, object : TypeToken>() {}.type + ) } + Log.d(kTag, authenticatedType.toJson()) + //获取权限内所有窨井数据 + } override fun initEvent() { + aMap = mapView.map + val uiSettings = aMap.uiSettings + uiSettings.isMyLocationButtonEnabled = true//设置默认定位按钮是否显示 + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 + //显示定位小蓝点 + val locationStyle = MyLocationStyle() + //连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动 + locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER) + locationStyle.showMyLocation(true)//设置是否显示定位小蓝点 + aMap.myLocationStyle = locationStyle + aMap.isMyLocationEnabled = true + + // 地图加载成功监听 + aMap.addOnMapLoadedListener(this) + // 位置改变监听 + aMap.addOnMyLocationChangeListener(this) + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker点击事件监听 + aMap.addOnMarkerClickListener(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + } + + override fun onMapLoaded() { + //地图加载成功之后显示聚合点数据 + initClustersMarkers() + } + + override fun onMyLocationChange(p0: Location?) { + if (p0 != null) { + this.location = LatLng(p0.latitude, p0.longitude) + } + } + + override fun onCameraChange(p0: CameraPosition?) { } + override fun onCameraChangeFinish(p0: CameraPosition?) { + //地图缩放之后显示聚合点数据 + initClustersMarkers() + } + + private fun initClustersMarkers() { + return + val proj = aMap.projection + val dm = resources.displayMetrics + var screenLocation: Point + markerOptionsInView.clear() + // 获取在当前视野内的marker + allMarkerOptions.forEach { + screenLocation = proj.toScreenLocation(it.position) + if (screenLocation.x >= 0 && screenLocation.y >= 0 && screenLocation.x <= dm.widthPixels && screenLocation.y <= dm.heightPixels) { + //在当前可观区域内 + markerOptionsInView.add(it) + } + } + // 自定义的聚合类MarkerCluster + val clustersMarkers: MutableList = ArrayList() + markerOptionsInView.forEach { + if (clustersMarkers.size == 0) { + //添加一个新的自定义marker + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80))//相距多少才聚合 + } else { + var isInRange = false + //Kotlin foreach不能用break + for (view in clustersMarkers) { + //判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。 + if (view.bounds.contains(it.position)) { + view.addMarker(it) + isInRange = true + break + } + } + //如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较 + if (!isInRange) { + //相距多少才聚合 + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80)) + } + } + } + // 设置聚合点的位置和icon + clustersMarkers.forEach { + it.setPositionAndIcon() + } + aMap.clear() + // 重新添加 marker + clustersMarkers.forEach { + aMap.addMarker(it.options) + } + } + + override fun onMarkerClick(marker: Marker?): Boolean { + val clickedLatLng = marker?.position + //判断点击点是否是定位点 + val distance = AMapUtils.calculateLineDistance(location, clickedLatLng) + if (distance > Constant.DISTANCE) { + //显示闸井信息 + marker!!.showInfoWindow() + } else { + "该位置是定位点,请选择实际闸井点".show() + } + return true + } + + override fun onInfoWindowClick(p0: Marker?) { + + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mapView.onCreate(savedInstanceState) } + override fun onResume() { super.onResume() mapView.onResume() diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index da8d67c..037fd9b 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -13,6 +13,7 @@ const val PERMISSIONS_CODE = 999 const val PAGE_LIMIT = 20 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val DISTANCE = 5 //两点间距离阈值,单位:米 val HOME_ICONS = arrayOf( R.drawable.ic_home_map, R.drawable.ic_home_record, R.drawable.ic_home_statistics, diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt index 1dea700..8401ec5 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt @@ -1,22 +1,52 @@ package com.casic.qd.smartwell.view +import android.graphics.Point +import android.location.Location import android.os.Bundle +import android.util.Log import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.* import com.casic.qd.smartwell.R import com.casic.qd.smartwell.base.BaseActivity +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toJson +import com.casic.qd.smartwell.utils.Constant +import com.casic.qd.smartwell.utils.SaveKeyValues +import com.casic.qd.smartwell.widgets.GaoDeClusterMarkerView +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import kotlinx.android.synthetic.main.activity_map.* import kotlinx.android.synthetic.main.include_base_title.* /** * @author a203 * @description 地图页面 - * @package com.casic.qd.smartwell.view * @date 2022/2/17 14:33 * @email 290677893@qq.com */ -class MapActivity : BaseActivity() { +class MapActivity : BaseActivity(), AMap.OnMapLoadedListener, AMap.OnMyLocationChangeListener, + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.OnInfoWindowClickListener { - private var aMap: AMap? = null + private val kTag = "MapActivity" + private var authenticatedType: MutableList = ArrayList() + private lateinit var aMap: AMap + + /** + * 定位点经纬度 + * */ + private lateinit var location: LatLng + + /** + * 所有的marker + */ + private var allMarkerOptions: MutableList = ArrayList() + + /** + * 视野内的marker + */ + private var markerOptionsInView: MutableList = ArrayList() override fun initLayoutView(): Int = R.layout.activity_map @@ -26,20 +56,136 @@ } override fun initData() { - if (aMap == null) { - aMap = mapView.map + val userDeviceJson = SaveKeyValues.getValue(Constant.USER_DEVICE_TYPE, "") as String + if (userDeviceJson.isNotBlank()) { + authenticatedType = Gson().fromJson( + userDeviceJson, object : TypeToken>() {}.type + ) } + Log.d(kTag, authenticatedType.toJson()) + //获取权限内所有窨井数据 + } override fun initEvent() { + aMap = mapView.map + val uiSettings = aMap.uiSettings + uiSettings.isMyLocationButtonEnabled = true//设置默认定位按钮是否显示 + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 + //显示定位小蓝点 + val locationStyle = MyLocationStyle() + //连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动 + locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER) + locationStyle.showMyLocation(true)//设置是否显示定位小蓝点 + aMap.myLocationStyle = locationStyle + aMap.isMyLocationEnabled = true + + // 地图加载成功监听 + aMap.addOnMapLoadedListener(this) + // 位置改变监听 + aMap.addOnMyLocationChangeListener(this) + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker点击事件监听 + aMap.addOnMarkerClickListener(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + } + + override fun onMapLoaded() { + //地图加载成功之后显示聚合点数据 + initClustersMarkers() + } + + override fun onMyLocationChange(p0: Location?) { + if (p0 != null) { + this.location = LatLng(p0.latitude, p0.longitude) + } + } + + override fun onCameraChange(p0: CameraPosition?) { } + override fun onCameraChangeFinish(p0: CameraPosition?) { + //地图缩放之后显示聚合点数据 + initClustersMarkers() + } + + private fun initClustersMarkers() { + return + val proj = aMap.projection + val dm = resources.displayMetrics + var screenLocation: Point + markerOptionsInView.clear() + // 获取在当前视野内的marker + allMarkerOptions.forEach { + screenLocation = proj.toScreenLocation(it.position) + if (screenLocation.x >= 0 && screenLocation.y >= 0 && screenLocation.x <= dm.widthPixels && screenLocation.y <= dm.heightPixels) { + //在当前可观区域内 + markerOptionsInView.add(it) + } + } + // 自定义的聚合类MarkerCluster + val clustersMarkers: MutableList = ArrayList() + markerOptionsInView.forEach { + if (clustersMarkers.size == 0) { + //添加一个新的自定义marker + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80))//相距多少才聚合 + } else { + var isInRange = false + //Kotlin foreach不能用break + for (view in clustersMarkers) { + //判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。 + if (view.bounds.contains(it.position)) { + view.addMarker(it) + isInRange = true + break + } + } + //如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较 + if (!isInRange) { + //相距多少才聚合 + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80)) + } + } + } + // 设置聚合点的位置和icon + clustersMarkers.forEach { + it.setPositionAndIcon() + } + aMap.clear() + // 重新添加 marker + clustersMarkers.forEach { + aMap.addMarker(it.options) + } + } + + override fun onMarkerClick(marker: Marker?): Boolean { + val clickedLatLng = marker?.position + //判断点击点是否是定位点 + val distance = AMapUtils.calculateLineDistance(location, clickedLatLng) + if (distance > Constant.DISTANCE) { + //显示闸井信息 + marker!!.showInfoWindow() + } else { + "该位置是定位点,请选择实际闸井点".show() + } + return true + } + + override fun onInfoWindowClick(p0: Marker?) { + + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mapView.onCreate(savedInstanceState) } + override fun onResume() { super.onResume() mapView.onResume() diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt new file mode 100644 index 0000000..8c723e6 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt @@ -0,0 +1,102 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Point +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import com.amap.api.maps.Projection +import com.amap.api.maps.model.BitmapDescriptorFactory +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.toBitmap +import java.util.* + +class GaoDeClusterMarkerView( + private val context: Context, firstMarkers: MarkerOptions, + projection: Projection, gridSize: Int +) { + //当前可观区域里的 聚合过之后的集合 + private val includeMarkers: ArrayList + + // 创建区域 + val bounds: LatLngBounds + var options: MarkerOptions = MarkerOptions() + + init { + val screenLocation = projection.toScreenLocation(firstMarkers.position) + //范围类 + val southwestPoint = Point(screenLocation.x - gridSize, screenLocation.y + gridSize) + //范围类 + val northeastPoint = Point(screenLocation.x + gridSize, screenLocation.y - gridSize) + bounds = LatLngBounds( + projection.fromScreenLocation(southwestPoint), + projection.fromScreenLocation(northeastPoint) + ) + //设置初始化marker属性 + options.anchor(0.5f, 1.3f) + .title(firstMarkers.title) + .position(firstMarkers.position) + .icon(firstMarkers.icon) + .snippet(firstMarkers.snippet) + .draggable(false) + includeMarkers = ArrayList() + includeMarkers.add(firstMarkers) + } + + /** + * 添加marker + */ + fun addMarker(markerOptions: MarkerOptions) { + includeMarkers.add(markerOptions) // 添加到列表中 + } + + /** + * 设置聚合点的中心位置以及图标 + */ + fun setPositionAndIcon() { + val size = includeMarkers.size + var lat = 0.0 + var lng = 0.0 + // 一个的时候 + if (size == 1) { //设置marker单个属性 + // 设置marker位置 + options.position( + LatLng( + includeMarkers[0].position.latitude, + includeMarkers[0].position.longitude + ) + ) + } else { // 聚合的时候 + //设置marker聚合属性 + for (op in includeMarkers) { + lat += op.position.latitude + lng += op.position.longitude + } + // 设置marker的位置为中心位置为聚集点的平均位置 + options.position(LatLng(lat / size, lng / size)) + } + options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap(size))) + } + + /** + * marker视图 + */ + private fun getBitmap(num: Int): Bitmap? { + val view = LayoutInflater.from(context).inflate(R.layout.marker_gaode, null) + val wellCountView = view.findViewById(R.id.wellCountView) + return if (num > 1) { + wellCountView.visibility = View.VISIBLE + wellCountView.text = String.format("${num}个") + wellCountView.gravity = Gravity.CENTER + view.toBitmap() + } else { + wellCountView.visibility = View.GONE + BitmapDescriptorFactory.fromResource(R.mipmap.well_location).bitmap + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index da8d67c..037fd9b 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -13,6 +13,7 @@ const val PERMISSIONS_CODE = 999 const val PAGE_LIMIT = 20 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val DISTANCE = 5 //两点间距离阈值,单位:米 val HOME_ICONS = arrayOf( R.drawable.ic_home_map, R.drawable.ic_home_record, R.drawable.ic_home_statistics, diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt index 1dea700..8401ec5 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt @@ -1,22 +1,52 @@ package com.casic.qd.smartwell.view +import android.graphics.Point +import android.location.Location import android.os.Bundle +import android.util.Log import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.* import com.casic.qd.smartwell.R import com.casic.qd.smartwell.base.BaseActivity +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toJson +import com.casic.qd.smartwell.utils.Constant +import com.casic.qd.smartwell.utils.SaveKeyValues +import com.casic.qd.smartwell.widgets.GaoDeClusterMarkerView +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import kotlinx.android.synthetic.main.activity_map.* import kotlinx.android.synthetic.main.include_base_title.* /** * @author a203 * @description 地图页面 - * @package com.casic.qd.smartwell.view * @date 2022/2/17 14:33 * @email 290677893@qq.com */ -class MapActivity : BaseActivity() { +class MapActivity : BaseActivity(), AMap.OnMapLoadedListener, AMap.OnMyLocationChangeListener, + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.OnInfoWindowClickListener { - private var aMap: AMap? = null + private val kTag = "MapActivity" + private var authenticatedType: MutableList = ArrayList() + private lateinit var aMap: AMap + + /** + * 定位点经纬度 + * */ + private lateinit var location: LatLng + + /** + * 所有的marker + */ + private var allMarkerOptions: MutableList = ArrayList() + + /** + * 视野内的marker + */ + private var markerOptionsInView: MutableList = ArrayList() override fun initLayoutView(): Int = R.layout.activity_map @@ -26,20 +56,136 @@ } override fun initData() { - if (aMap == null) { - aMap = mapView.map + val userDeviceJson = SaveKeyValues.getValue(Constant.USER_DEVICE_TYPE, "") as String + if (userDeviceJson.isNotBlank()) { + authenticatedType = Gson().fromJson( + userDeviceJson, object : TypeToken>() {}.type + ) } + Log.d(kTag, authenticatedType.toJson()) + //获取权限内所有窨井数据 + } override fun initEvent() { + aMap = mapView.map + val uiSettings = aMap.uiSettings + uiSettings.isMyLocationButtonEnabled = true//设置默认定位按钮是否显示 + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 + //显示定位小蓝点 + val locationStyle = MyLocationStyle() + //连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动 + locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER) + locationStyle.showMyLocation(true)//设置是否显示定位小蓝点 + aMap.myLocationStyle = locationStyle + aMap.isMyLocationEnabled = true + + // 地图加载成功监听 + aMap.addOnMapLoadedListener(this) + // 位置改变监听 + aMap.addOnMyLocationChangeListener(this) + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker点击事件监听 + aMap.addOnMarkerClickListener(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + } + + override fun onMapLoaded() { + //地图加载成功之后显示聚合点数据 + initClustersMarkers() + } + + override fun onMyLocationChange(p0: Location?) { + if (p0 != null) { + this.location = LatLng(p0.latitude, p0.longitude) + } + } + + override fun onCameraChange(p0: CameraPosition?) { } + override fun onCameraChangeFinish(p0: CameraPosition?) { + //地图缩放之后显示聚合点数据 + initClustersMarkers() + } + + private fun initClustersMarkers() { + return + val proj = aMap.projection + val dm = resources.displayMetrics + var screenLocation: Point + markerOptionsInView.clear() + // 获取在当前视野内的marker + allMarkerOptions.forEach { + screenLocation = proj.toScreenLocation(it.position) + if (screenLocation.x >= 0 && screenLocation.y >= 0 && screenLocation.x <= dm.widthPixels && screenLocation.y <= dm.heightPixels) { + //在当前可观区域内 + markerOptionsInView.add(it) + } + } + // 自定义的聚合类MarkerCluster + val clustersMarkers: MutableList = ArrayList() + markerOptionsInView.forEach { + if (clustersMarkers.size == 0) { + //添加一个新的自定义marker + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80))//相距多少才聚合 + } else { + var isInRange = false + //Kotlin foreach不能用break + for (view in clustersMarkers) { + //判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。 + if (view.bounds.contains(it.position)) { + view.addMarker(it) + isInRange = true + break + } + } + //如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较 + if (!isInRange) { + //相距多少才聚合 + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80)) + } + } + } + // 设置聚合点的位置和icon + clustersMarkers.forEach { + it.setPositionAndIcon() + } + aMap.clear() + // 重新添加 marker + clustersMarkers.forEach { + aMap.addMarker(it.options) + } + } + + override fun onMarkerClick(marker: Marker?): Boolean { + val clickedLatLng = marker?.position + //判断点击点是否是定位点 + val distance = AMapUtils.calculateLineDistance(location, clickedLatLng) + if (distance > Constant.DISTANCE) { + //显示闸井信息 + marker!!.showInfoWindow() + } else { + "该位置是定位点,请选择实际闸井点".show() + } + return true + } + + override fun onInfoWindowClick(p0: Marker?) { + + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mapView.onCreate(savedInstanceState) } + override fun onResume() { super.onResume() mapView.onResume() diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt new file mode 100644 index 0000000..8c723e6 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt @@ -0,0 +1,102 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Point +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import com.amap.api.maps.Projection +import com.amap.api.maps.model.BitmapDescriptorFactory +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.toBitmap +import java.util.* + +class GaoDeClusterMarkerView( + private val context: Context, firstMarkers: MarkerOptions, + projection: Projection, gridSize: Int +) { + //当前可观区域里的 聚合过之后的集合 + private val includeMarkers: ArrayList + + // 创建区域 + val bounds: LatLngBounds + var options: MarkerOptions = MarkerOptions() + + init { + val screenLocation = projection.toScreenLocation(firstMarkers.position) + //范围类 + val southwestPoint = Point(screenLocation.x - gridSize, screenLocation.y + gridSize) + //范围类 + val northeastPoint = Point(screenLocation.x + gridSize, screenLocation.y - gridSize) + bounds = LatLngBounds( + projection.fromScreenLocation(southwestPoint), + projection.fromScreenLocation(northeastPoint) + ) + //设置初始化marker属性 + options.anchor(0.5f, 1.3f) + .title(firstMarkers.title) + .position(firstMarkers.position) + .icon(firstMarkers.icon) + .snippet(firstMarkers.snippet) + .draggable(false) + includeMarkers = ArrayList() + includeMarkers.add(firstMarkers) + } + + /** + * 添加marker + */ + fun addMarker(markerOptions: MarkerOptions) { + includeMarkers.add(markerOptions) // 添加到列表中 + } + + /** + * 设置聚合点的中心位置以及图标 + */ + fun setPositionAndIcon() { + val size = includeMarkers.size + var lat = 0.0 + var lng = 0.0 + // 一个的时候 + if (size == 1) { //设置marker单个属性 + // 设置marker位置 + options.position( + LatLng( + includeMarkers[0].position.latitude, + includeMarkers[0].position.longitude + ) + ) + } else { // 聚合的时候 + //设置marker聚合属性 + for (op in includeMarkers) { + lat += op.position.latitude + lng += op.position.longitude + } + // 设置marker的位置为中心位置为聚集点的平均位置 + options.position(LatLng(lat / size, lng / size)) + } + options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap(size))) + } + + /** + * marker视图 + */ + private fun getBitmap(num: Int): Bitmap? { + val view = LayoutInflater.from(context).inflate(R.layout.marker_gaode, null) + val wellCountView = view.findViewById(R.id.wellCountView) + return if (num > 1) { + wellCountView.visibility = View.VISIBLE + wellCountView.text = String.format("${num}个") + wellCountView.gravity = Gravity.CENTER + view.toBitmap() + } else { + wellCountView.visibility = View.GONE + BitmapDescriptorFactory.fromResource(R.mipmap.well_location).bitmap + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/marker_gaode.xml b/app/src/main/res/layout/marker_gaode.xml new file mode 100644 index 0000000..ea46f09 --- /dev/null +++ b/app/src/main/res/layout/marker_gaode.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index da8d67c..037fd9b 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -13,6 +13,7 @@ const val PERMISSIONS_CODE = 999 const val PAGE_LIMIT = 20 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val DISTANCE = 5 //两点间距离阈值,单位:米 val HOME_ICONS = arrayOf( R.drawable.ic_home_map, R.drawable.ic_home_record, R.drawable.ic_home_statistics, diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt index 1dea700..8401ec5 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt @@ -1,22 +1,52 @@ package com.casic.qd.smartwell.view +import android.graphics.Point +import android.location.Location import android.os.Bundle +import android.util.Log import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.* import com.casic.qd.smartwell.R import com.casic.qd.smartwell.base.BaseActivity +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toJson +import com.casic.qd.smartwell.utils.Constant +import com.casic.qd.smartwell.utils.SaveKeyValues +import com.casic.qd.smartwell.widgets.GaoDeClusterMarkerView +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import kotlinx.android.synthetic.main.activity_map.* import kotlinx.android.synthetic.main.include_base_title.* /** * @author a203 * @description 地图页面 - * @package com.casic.qd.smartwell.view * @date 2022/2/17 14:33 * @email 290677893@qq.com */ -class MapActivity : BaseActivity() { +class MapActivity : BaseActivity(), AMap.OnMapLoadedListener, AMap.OnMyLocationChangeListener, + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.OnInfoWindowClickListener { - private var aMap: AMap? = null + private val kTag = "MapActivity" + private var authenticatedType: MutableList = ArrayList() + private lateinit var aMap: AMap + + /** + * 定位点经纬度 + * */ + private lateinit var location: LatLng + + /** + * 所有的marker + */ + private var allMarkerOptions: MutableList = ArrayList() + + /** + * 视野内的marker + */ + private var markerOptionsInView: MutableList = ArrayList() override fun initLayoutView(): Int = R.layout.activity_map @@ -26,20 +56,136 @@ } override fun initData() { - if (aMap == null) { - aMap = mapView.map + val userDeviceJson = SaveKeyValues.getValue(Constant.USER_DEVICE_TYPE, "") as String + if (userDeviceJson.isNotBlank()) { + authenticatedType = Gson().fromJson( + userDeviceJson, object : TypeToken>() {}.type + ) } + Log.d(kTag, authenticatedType.toJson()) + //获取权限内所有窨井数据 + } override fun initEvent() { + aMap = mapView.map + val uiSettings = aMap.uiSettings + uiSettings.isMyLocationButtonEnabled = true//设置默认定位按钮是否显示 + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 + //显示定位小蓝点 + val locationStyle = MyLocationStyle() + //连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动 + locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER) + locationStyle.showMyLocation(true)//设置是否显示定位小蓝点 + aMap.myLocationStyle = locationStyle + aMap.isMyLocationEnabled = true + + // 地图加载成功监听 + aMap.addOnMapLoadedListener(this) + // 位置改变监听 + aMap.addOnMyLocationChangeListener(this) + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker点击事件监听 + aMap.addOnMarkerClickListener(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + } + + override fun onMapLoaded() { + //地图加载成功之后显示聚合点数据 + initClustersMarkers() + } + + override fun onMyLocationChange(p0: Location?) { + if (p0 != null) { + this.location = LatLng(p0.latitude, p0.longitude) + } + } + + override fun onCameraChange(p0: CameraPosition?) { } + override fun onCameraChangeFinish(p0: CameraPosition?) { + //地图缩放之后显示聚合点数据 + initClustersMarkers() + } + + private fun initClustersMarkers() { + return + val proj = aMap.projection + val dm = resources.displayMetrics + var screenLocation: Point + markerOptionsInView.clear() + // 获取在当前视野内的marker + allMarkerOptions.forEach { + screenLocation = proj.toScreenLocation(it.position) + if (screenLocation.x >= 0 && screenLocation.y >= 0 && screenLocation.x <= dm.widthPixels && screenLocation.y <= dm.heightPixels) { + //在当前可观区域内 + markerOptionsInView.add(it) + } + } + // 自定义的聚合类MarkerCluster + val clustersMarkers: MutableList = ArrayList() + markerOptionsInView.forEach { + if (clustersMarkers.size == 0) { + //添加一个新的自定义marker + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80))//相距多少才聚合 + } else { + var isInRange = false + //Kotlin foreach不能用break + for (view in clustersMarkers) { + //判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。 + if (view.bounds.contains(it.position)) { + view.addMarker(it) + isInRange = true + break + } + } + //如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较 + if (!isInRange) { + //相距多少才聚合 + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80)) + } + } + } + // 设置聚合点的位置和icon + clustersMarkers.forEach { + it.setPositionAndIcon() + } + aMap.clear() + // 重新添加 marker + clustersMarkers.forEach { + aMap.addMarker(it.options) + } + } + + override fun onMarkerClick(marker: Marker?): Boolean { + val clickedLatLng = marker?.position + //判断点击点是否是定位点 + val distance = AMapUtils.calculateLineDistance(location, clickedLatLng) + if (distance > Constant.DISTANCE) { + //显示闸井信息 + marker!!.showInfoWindow() + } else { + "该位置是定位点,请选择实际闸井点".show() + } + return true + } + + override fun onInfoWindowClick(p0: Marker?) { + + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mapView.onCreate(savedInstanceState) } + override fun onResume() { super.onResume() mapView.onResume() diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt new file mode 100644 index 0000000..8c723e6 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt @@ -0,0 +1,102 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Point +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import com.amap.api.maps.Projection +import com.amap.api.maps.model.BitmapDescriptorFactory +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.toBitmap +import java.util.* + +class GaoDeClusterMarkerView( + private val context: Context, firstMarkers: MarkerOptions, + projection: Projection, gridSize: Int +) { + //当前可观区域里的 聚合过之后的集合 + private val includeMarkers: ArrayList + + // 创建区域 + val bounds: LatLngBounds + var options: MarkerOptions = MarkerOptions() + + init { + val screenLocation = projection.toScreenLocation(firstMarkers.position) + //范围类 + val southwestPoint = Point(screenLocation.x - gridSize, screenLocation.y + gridSize) + //范围类 + val northeastPoint = Point(screenLocation.x + gridSize, screenLocation.y - gridSize) + bounds = LatLngBounds( + projection.fromScreenLocation(southwestPoint), + projection.fromScreenLocation(northeastPoint) + ) + //设置初始化marker属性 + options.anchor(0.5f, 1.3f) + .title(firstMarkers.title) + .position(firstMarkers.position) + .icon(firstMarkers.icon) + .snippet(firstMarkers.snippet) + .draggable(false) + includeMarkers = ArrayList() + includeMarkers.add(firstMarkers) + } + + /** + * 添加marker + */ + fun addMarker(markerOptions: MarkerOptions) { + includeMarkers.add(markerOptions) // 添加到列表中 + } + + /** + * 设置聚合点的中心位置以及图标 + */ + fun setPositionAndIcon() { + val size = includeMarkers.size + var lat = 0.0 + var lng = 0.0 + // 一个的时候 + if (size == 1) { //设置marker单个属性 + // 设置marker位置 + options.position( + LatLng( + includeMarkers[0].position.latitude, + includeMarkers[0].position.longitude + ) + ) + } else { // 聚合的时候 + //设置marker聚合属性 + for (op in includeMarkers) { + lat += op.position.latitude + lng += op.position.longitude + } + // 设置marker的位置为中心位置为聚集点的平均位置 + options.position(LatLng(lat / size, lng / size)) + } + options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap(size))) + } + + /** + * marker视图 + */ + private fun getBitmap(num: Int): Bitmap? { + val view = LayoutInflater.from(context).inflate(R.layout.marker_gaode, null) + val wellCountView = view.findViewById(R.id.wellCountView) + return if (num > 1) { + wellCountView.visibility = View.VISIBLE + wellCountView.text = String.format("${num}个") + wellCountView.gravity = Gravity.CENTER + view.toBitmap() + } else { + wellCountView.visibility = View.GONE + BitmapDescriptorFactory.fromResource(R.mipmap.well_location).bitmap + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/marker_gaode.xml b/app/src/main/res/layout/marker_gaode.xml new file mode 100644 index 0000000..ea46f09 --- /dev/null +++ b/app/src/main/res/layout/marker_gaode.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxhdpi/popup.png b/app/src/main/res/mipmap-xxhdpi/popup.png new file mode 100644 index 0000000..8700aef --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/popup.png Binary files differ diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt new file mode 100644 index 0000000..45ff117 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/View.kt @@ -0,0 +1,23 @@ +package com.casic.qd.smartwell.extensions + +import android.graphics.Bitmap +import android.view.View + +/** + * 把一个view转化成bitmap对象 + */ +fun View.toBitmap(): Bitmap? { + var bitmap: Bitmap? = null + try { + this.measure( + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) + ) + this.layout(0, 0, this.measuredWidth, this.measuredHeight) + this.buildDrawingCache() + bitmap = this.drawingCache + } catch (e: Exception) { + e.printStackTrace() + } + return bitmap +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt index da8d67c..037fd9b 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/Constant.kt @@ -13,6 +13,7 @@ const val PERMISSIONS_CODE = 999 const val PAGE_LIMIT = 20 const val FIVE_YEARS = 5L * 365 * 60 * 60 * 24 * 1000L + const val DISTANCE = 5 //两点间距离阈值,单位:米 val HOME_ICONS = arrayOf( R.drawable.ic_home_map, R.drawable.ic_home_record, R.drawable.ic_home_statistics, diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt index 1dea700..8401ec5 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MapActivity.kt @@ -1,22 +1,52 @@ package com.casic.qd.smartwell.view +import android.graphics.Point +import android.location.Location import android.os.Bundle +import android.util.Log import com.amap.api.maps.AMap +import com.amap.api.maps.AMapOptions +import com.amap.api.maps.AMapUtils +import com.amap.api.maps.model.* import com.casic.qd.smartwell.R import com.casic.qd.smartwell.base.BaseActivity +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toJson +import com.casic.qd.smartwell.utils.Constant +import com.casic.qd.smartwell.utils.SaveKeyValues +import com.casic.qd.smartwell.widgets.GaoDeClusterMarkerView +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import kotlinx.android.synthetic.main.activity_map.* import kotlinx.android.synthetic.main.include_base_title.* /** * @author a203 * @description 地图页面 - * @package com.casic.qd.smartwell.view * @date 2022/2/17 14:33 * @email 290677893@qq.com */ -class MapActivity : BaseActivity() { +class MapActivity : BaseActivity(), AMap.OnMapLoadedListener, AMap.OnMyLocationChangeListener, + AMap.OnCameraChangeListener, AMap.OnMarkerClickListener, AMap.OnInfoWindowClickListener { - private var aMap: AMap? = null + private val kTag = "MapActivity" + private var authenticatedType: MutableList = ArrayList() + private lateinit var aMap: AMap + + /** + * 定位点经纬度 + * */ + private lateinit var location: LatLng + + /** + * 所有的marker + */ + private var allMarkerOptions: MutableList = ArrayList() + + /** + * 视野内的marker + */ + private var markerOptionsInView: MutableList = ArrayList() override fun initLayoutView(): Int = R.layout.activity_map @@ -26,20 +56,136 @@ } override fun initData() { - if (aMap == null) { - aMap = mapView.map + val userDeviceJson = SaveKeyValues.getValue(Constant.USER_DEVICE_TYPE, "") as String + if (userDeviceJson.isNotBlank()) { + authenticatedType = Gson().fromJson( + userDeviceJson, object : TypeToken>() {}.type + ) } + Log.d(kTag, authenticatedType.toJson()) + //获取权限内所有窨井数据 + } override fun initEvent() { + aMap = mapView.map + val uiSettings = aMap.uiSettings + uiSettings.isMyLocationButtonEnabled = true//设置默认定位按钮是否显示 + uiSettings.isCompassEnabled = true + uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER + uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度 + uiSettings.isRotateGesturesEnabled = false//不许地图随手势旋转角度 + //显示定位小蓝点 + val locationStyle = MyLocationStyle() + //连续定位、蓝点不会移动到地图中心点,定位点依照设备方向旋转,并且蓝点会跟随设备移动 + locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER) + locationStyle.showMyLocation(true)//设置是否显示定位小蓝点 + aMap.myLocationStyle = locationStyle + aMap.isMyLocationEnabled = true + + // 地图加载成功监听 + aMap.addOnMapLoadedListener(this) + // 位置改变监听 + aMap.addOnMyLocationChangeListener(this) + // 地图缩放监听 + aMap.addOnCameraChangeListener(this) + // marker点击事件监听 + aMap.addOnMarkerClickListener(this) + //信息窗点击事件 + aMap.addOnInfoWindowClickListener(this) + } + + override fun onMapLoaded() { + //地图加载成功之后显示聚合点数据 + initClustersMarkers() + } + + override fun onMyLocationChange(p0: Location?) { + if (p0 != null) { + this.location = LatLng(p0.latitude, p0.longitude) + } + } + + override fun onCameraChange(p0: CameraPosition?) { } + override fun onCameraChangeFinish(p0: CameraPosition?) { + //地图缩放之后显示聚合点数据 + initClustersMarkers() + } + + private fun initClustersMarkers() { + return + val proj = aMap.projection + val dm = resources.displayMetrics + var screenLocation: Point + markerOptionsInView.clear() + // 获取在当前视野内的marker + allMarkerOptions.forEach { + screenLocation = proj.toScreenLocation(it.position) + if (screenLocation.x >= 0 && screenLocation.y >= 0 && screenLocation.x <= dm.widthPixels && screenLocation.y <= dm.heightPixels) { + //在当前可观区域内 + markerOptionsInView.add(it) + } + } + // 自定义的聚合类MarkerCluster + val clustersMarkers: MutableList = ArrayList() + markerOptionsInView.forEach { + if (clustersMarkers.size == 0) { + //添加一个新的自定义marker + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80))//相距多少才聚合 + } else { + var isInRange = false + //Kotlin foreach不能用break + for (view in clustersMarkers) { + //判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。 + if (view.bounds.contains(it.position)) { + view.addMarker(it) + isInRange = true + break + } + } + //如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较 + if (!isInRange) { + //相距多少才聚合 + clustersMarkers.add(GaoDeClusterMarkerView(this, it, proj, 80)) + } + } + } + // 设置聚合点的位置和icon + clustersMarkers.forEach { + it.setPositionAndIcon() + } + aMap.clear() + // 重新添加 marker + clustersMarkers.forEach { + aMap.addMarker(it.options) + } + } + + override fun onMarkerClick(marker: Marker?): Boolean { + val clickedLatLng = marker?.position + //判断点击点是否是定位点 + val distance = AMapUtils.calculateLineDistance(location, clickedLatLng) + if (distance > Constant.DISTANCE) { + //显示闸井信息 + marker!!.showInfoWindow() + } else { + "该位置是定位点,请选择实际闸井点".show() + } + return true + } + + override fun onInfoWindowClick(p0: Marker?) { + + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mapView.onCreate(savedInstanceState) } + override fun onResume() { super.onResume() mapView.onResume() diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt new file mode 100644 index 0000000..8c723e6 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/GaoDeClusterMarkerView.kt @@ -0,0 +1,102 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Point +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import com.amap.api.maps.Projection +import com.amap.api.maps.model.BitmapDescriptorFactory +import com.amap.api.maps.model.LatLng +import com.amap.api.maps.model.LatLngBounds +import com.amap.api.maps.model.MarkerOptions +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.toBitmap +import java.util.* + +class GaoDeClusterMarkerView( + private val context: Context, firstMarkers: MarkerOptions, + projection: Projection, gridSize: Int +) { + //当前可观区域里的 聚合过之后的集合 + private val includeMarkers: ArrayList + + // 创建区域 + val bounds: LatLngBounds + var options: MarkerOptions = MarkerOptions() + + init { + val screenLocation = projection.toScreenLocation(firstMarkers.position) + //范围类 + val southwestPoint = Point(screenLocation.x - gridSize, screenLocation.y + gridSize) + //范围类 + val northeastPoint = Point(screenLocation.x + gridSize, screenLocation.y - gridSize) + bounds = LatLngBounds( + projection.fromScreenLocation(southwestPoint), + projection.fromScreenLocation(northeastPoint) + ) + //设置初始化marker属性 + options.anchor(0.5f, 1.3f) + .title(firstMarkers.title) + .position(firstMarkers.position) + .icon(firstMarkers.icon) + .snippet(firstMarkers.snippet) + .draggable(false) + includeMarkers = ArrayList() + includeMarkers.add(firstMarkers) + } + + /** + * 添加marker + */ + fun addMarker(markerOptions: MarkerOptions) { + includeMarkers.add(markerOptions) // 添加到列表中 + } + + /** + * 设置聚合点的中心位置以及图标 + */ + fun setPositionAndIcon() { + val size = includeMarkers.size + var lat = 0.0 + var lng = 0.0 + // 一个的时候 + if (size == 1) { //设置marker单个属性 + // 设置marker位置 + options.position( + LatLng( + includeMarkers[0].position.latitude, + includeMarkers[0].position.longitude + ) + ) + } else { // 聚合的时候 + //设置marker聚合属性 + for (op in includeMarkers) { + lat += op.position.latitude + lng += op.position.longitude + } + // 设置marker的位置为中心位置为聚集点的平均位置 + options.position(LatLng(lat / size, lng / size)) + } + options.icon(BitmapDescriptorFactory.fromBitmap(getBitmap(size))) + } + + /** + * marker视图 + */ + private fun getBitmap(num: Int): Bitmap? { + val view = LayoutInflater.from(context).inflate(R.layout.marker_gaode, null) + val wellCountView = view.findViewById(R.id.wellCountView) + return if (num > 1) { + wellCountView.visibility = View.VISIBLE + wellCountView.text = String.format("${num}个") + wellCountView.gravity = Gravity.CENTER + view.toBitmap() + } else { + wellCountView.visibility = View.GONE + BitmapDescriptorFactory.fromResource(R.mipmap.well_location).bitmap + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/marker_gaode.xml b/app/src/main/res/layout/marker_gaode.xml new file mode 100644 index 0000000..ea46f09 --- /dev/null +++ b/app/src/main/res/layout/marker_gaode.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxhdpi/popup.png b/app/src/main/res/mipmap-xxhdpi/popup.png new file mode 100644 index 0000000..8700aef --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/popup.png Binary files differ diff --git a/app/src/main/res/mipmap-xxhdpi/well_location.png b/app/src/main/res/mipmap-xxhdpi/well_location.png new file mode 100644 index 0000000..483687f --- /dev/null +++ b/app/src/main/res/mipmap-xxhdpi/well_location.png Binary files differ