Newer
Older
CasicSmartTube / app / src / main / java / com / casic / smarttube / fragment / HomePageFragment.kt
package com.casic.smarttube.fragment

import android.graphics.Point
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.amap.api.maps.AMap
import com.amap.api.maps.AMapOptions
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.CoordinateConverter
import com.amap.api.maps.model.*
import com.casic.smarttube.R
import com.casic.smarttube.model.MapDeviceModel
import com.casic.smarttube.utils.DialogHelper
import com.casic.smarttube.utils.LocaleConstant
import com.casic.smarttube.view.AddDeviceActivity
import com.casic.smarttube.vm.DeviceViewModel
import com.casic.smarttube.widgets.GaoDeClusterMarkerView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.pengxh.kt.lite.extensions.*
import com.pengxh.kt.lite.widget.EasyPopupWindow
import com.pengxh.kt.lite.widget.dialog.AlertControlDialog
import kotlinx.android.synthetic.main.fragment_home.view.*

class HomePageFragment : Fragment(), AMap.OnMapLoadedListener, AMap.OnCameraChangeListener,
    AMap.OnMarkerClickListener, AMap.InfoWindowAdapter, AMap.OnInfoWindowClickListener {

    private val kTag = "HomePageFragment"
    private lateinit var homeView: View
    private lateinit var aMap: AMap
    private lateinit var deviceViewModel: DeviceViewModel

    /**
     * 所有的marker
     */
    private var allMarkerOptions: MutableList<MarkerOptions> = ArrayList()

    /**
     * 视野内的marker
     */
    private var markerOptionsInView: MutableList<MarkerOptions> = ArrayList()

    /**
     * 自定义Marker弹出框
     * */
    private var infoWindow: View? = null

    /**
     * 所有设备列表信息集合
     * */
    private var deviceModels: MutableList<MapDeviceModel.DataBean> = ArrayList()

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        homeView = inflater.inflate(R.layout.fragment_home, container, false)

        val easyPopupWindow = EasyPopupWindow(requireContext())
        easyPopupWindow.setPopupMenuItem(LocaleConstant.POPUP_IMAGES, LocaleConstant.POPUP_TITLES)
        homeView.rightOptionView.setOnClickListener {
            easyPopupWindow.setOnPopupWindowClickListener(object :
                EasyPopupWindow.OnPopupWindowClickListener {
                override fun onPopupItemClicked(position: Int) {
                    when (position) {
                        0 -> aMap.mapType = AMap.MAP_TYPE_NORMAL
                        1 -> aMap.mapType = AMap.MAP_TYPE_SATELLITE
                    }
                }
            })
            easyPopupWindow.setBackgroundDrawable(null)
            val x: Int = homeView.rightOptionView.width - easyPopupWindow.width
            easyPopupWindow.showAsDropDown(homeView.rightOptionView, x, 0)
        }

        //代码设置底部拉升距离
        val bottomSheetBehavior = BottomSheetBehavior.from(homeView.bottomBehaviorLayout)
        homeView.coordinatorLayout.post {
            bottomSheetBehavior.isFitToContents = false
            bottomSheetBehavior.peekHeight = 30f.dp2px(requireContext())
            bottomSheetBehavior.isHideable = false
        }

        //初始化vm
        deviceViewModel = ViewModelProvider(this).get(DeviceViewModel::class.java)

        //获取所有窨井数据
        httpCountDownTimer.start()
        DialogHelper.showLoadingDialog(requireActivity(), "数据加载中,请稍后...")
        //获取所有设备数据
        deviceViewModel.obtainMapDeviceList()
        deviceViewModel.mapDeviceModel.observe(this, {
            if (it.code == 200) {
                val latitudeList: MutableList<Double> = ArrayList()
                val longitudeList: MutableList<Double> = ArrayList()
                it.data.forEach { device ->
                    val lat = device.latGaode.toString()
                    val lng = device.lngGaode.toString()
                    if (lat.isNotBlank() && lng.isNotBlank()) {
                        //返回true代表当前位置在大陆、港澳地区,反之不在
                        val latitude = lat.toDouble()
                        val longitude = lng.toDouble()
                        if (CoordinateConverter.isAMapDataAvailable(latitude, longitude)) {
                            //缓存所有设备详情,点击Marker时候需要
                            deviceModels.add(device)
                            //分别缓存经、纬度
                            latitudeList.add(latitude)
                            longitudeList.add(longitude)
                            //将所有设备信息转化缓存为Marker点
                            allMarkerOptions.add(
                                MarkerOptions()
                                    .position(LatLng(latitude, longitude))
                                    .title(device.wellName)
                                    .snippet(device.wellCode)
                            )
                        } else {
                            Log.d(kTag, "${device.wellCode}闸井经纬度不在国内,异常经纬度 ===> [${lng},${lat}]")
                        }
                    } else {
                        Log.d(kTag, "${device.wellCode}闸井经纬度异常,异常经纬度 ===> [${lng},${lat}]")
                    }
                }
                //计算所有点的中心点位置
                val centerLatLng = LatLng(latitudeList.average(), longitudeList.average())
                //移动到指定经纬度
                val cameraPosition = CameraPosition(centerLatLng, 12f, 0f, 0f)
                val cameraUpdate = CameraUpdateFactory.newCameraPosition(cameraPosition)
                aMap.animateCamera(cameraUpdate, 1500, null)
            }
        })

        //地图初始化
        initMap(savedInstanceState)

        homeView.addDeviceButton.setOnClickListener {
            requireContext().navigatePageTo<AddDeviceActivity>()
        }
        return homeView
    }

    private fun initMap(savedInstanceState: Bundle?) {
        homeView.mapView.onCreate(savedInstanceState)
        aMap = homeView.mapView.map
        aMap.mapType = AMap.MAP_TYPE_NORMAL
        val uiSettings = aMap.uiSettings
        uiSettings.isCompassEnabled = true
        uiSettings.zoomPosition = AMapOptions.ZOOM_POSITION_RIGHT_CENTER
        uiSettings.isZoomControlsEnabled = false//不显示+/-
        uiSettings.isTiltGesturesEnabled = false//不许地图随手势倾斜角度
        uiSettings.isRotateGesturesEnabled = false//不允许地图旋转

        // 地图加载成功监听
        aMap.addOnMapLoadedListener(this)
        // 地图缩放监听
        aMap.addOnCameraChangeListener(this)
        // marker 点击事件监听
        aMap.addOnMarkerClickListener(this)
        // 点击marker弹出自定义popup
        aMap.setInfoWindowAdapter(this)
    }

    override fun onMapLoaded() {
        //地图加载成功之后显示聚合点数据
        initClustersMarkers()
    }

    override fun onCameraChange(p0: CameraPosition?) {

    }

    /**
     * http请求计时器
     * */
    private val httpCountDownTimer = object : CountDownTimer(15 * 1000, 1000) {
        override fun onFinish() {
            "请求服务器超时,请退出后重试".show(requireContext())
            DialogHelper.dismissLoadingDialog()
        }

        override fun onTick(millisUntilFinished: Long) {

        }
    }

    //获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker
    override fun onCameraChangeFinish(p0: CameraPosition?) {
        //地图缩放之后显示聚合点数据
        DialogHelper.dismissLoadingDialog()
        httpCountDownTimer.cancel()
        initClustersMarkers()
    }

    private fun initClustersMarkers() {
        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<GaoDeClusterMarkerView> = ArrayList()
        markerOptionsInView.forEach {
            if (clustersMarkers.size == 0) {
                //添加一个新的自定义marker
                clustersMarkers.add(
                    GaoDeClusterMarkerView(requireContext(), it, proj, LocaleConstant.RADIUS_SIZE)
                )
            } 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(
                            requireContext(),
                            it,
                            proj,
                            LocaleConstant.RADIUS_SIZE
                        )
                    )//相距多少才聚合
                }
            }
        }
        // 设置聚合点的位置和icon
        clustersMarkers.forEach {
            it.setPositionAndIcon()
        }
        aMap.clear()
        // 重新添加 marker
        clustersMarkers.forEach {
            aMap.addMarker(it.options)
        }
    }

    override fun onMarkerClick(marker: Marker?): Boolean {
        //显示闸井信息
        marker?.showInfoWindow()
        return true
    }

    override fun getInfoWindow(marker: Marker?): View? {
        if (infoWindow == null) {
            infoWindow = LayoutInflater.from(requireContext()).inflate(R.layout.popu_map_info, null)
        }
        val v = infoWindow!!
        //反射得到popup里面的控件对象
        val wellNameView = v.findViewById<TextView>(R.id.wellNameView)
        val wellCodeView = v.findViewById<TextView>(R.id.wellCodeView)
        val wellTypeView = v.findViewById<TextView>(R.id.wellTypeView)
        val wellStateView = v.findViewById<TextView>(R.id.wellStateView)
        val deepView = v.findViewById<TextView>(R.id.deepView)
        val locationView = v.findViewById<TextView>(R.id.locationView)

        //绑定数据
        val clickedLatLng = marker?.position!!
        for (device in deviceModels) {
            if (clickedLatLng.latitude == device.latGaode!!.toDouble()
                && clickedLatLng.longitude == device.lngGaode!!.toDouble()
            ) {
                wellCodeView.text = String.format("闸井编号: ${device.wellCode}")
                wellNameView.text = String.format("闸井名称: ${device.wellName}")
                wellTypeView.text = String.format("闸井类型: ${device.wellType}")
                wellStateView.text = String.format("布/撤防状态: ${device.bfzt}")
                deepView.text = String.format("闸井深度: ${device.deep}m")
                locationView.text = String.format("详细位置: ${device.position}")
                return infoWindow
            }
        }
        "无法查看聚合点,请放大比例后再查看".show(requireContext())
        return null
    }

    /**
     * 此方法不能修改整个 InfoWindow 的背景和边框,无论自定义的样式是什么样,SDK 都会在最外层添加一个默认的边框
     * */
    override fun getInfoContents(p0: Marker?): View? = null

    override fun onInfoWindowClick(p0: Marker?) {
        if (p0 != null) {
            AlertControlDialog.Builder()
                .setContext(requireContext())
                .setTitle("操作提示")
                .setMessage("确定要前往吗")
                .setNegativeButton("取消")
                .setPositiveButton("确定")
                .setOnDialogButtonClickListener(object :
                    AlertControlDialog.OnDialogButtonClickListener {
                    override fun onConfirmClick() {
                        val latLng = p0.position
                        val lat = latLng.latitude.toString()
                        val lng = latLng.longitude.toString()
                        if (lat.isBlank() || lng.isBlank()) {
                            "窨井经纬度异常,无法开启导航".show(requireContext())
                            return
                        }
                        Poi(p0.snippet, LatLng(lat.toDouble(), lng.toDouble()), "").showRouteOnMap(
                            requireContext()
                        )
                    }

                    override fun onCancelClick() {

                    }
                }).build().show()
        }
    }

    /***以下是地图生命周期管理************************************************************************/
    override fun onResume() {
        super.onResume()
        homeView.mapView.onResume()
    }

    override fun onPause() {
        super.onPause()
        homeView.mapView.onPause()
    }

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

    override fun onDestroy() {
        super.onDestroy()
        homeView.mapView.onDestroy()
    }
}