Android高德地图定位实现签到打卡功能(全网最详细+收藏)

news2024/9/29 21:31:44

前言
        本章根据高德地图API,实现打卡签到功能。用到了定位SDK 和地图SDK、覆盖物。打卡范围图形可以支持多种形状,如:圆形长方形多边形。

核心逻辑:

    获取当前定位信息,然后通过Marker绘制小图标进行展示,并在onLocationChanged回调方法中不断重新绘制当前位置Marker以保持时时最新。在指定打卡签到区域添加围栏,主要使用CircleOptions、PolygonOptions进行绘制,然后判断当前是否在打卡范围内,具体实现如下。

PS:另外提一句,也可以结合+电子围栏进行广播自动触发自动打卡

目录

1、添加高德地图SDK到项目依赖中

2、获取定位权限

3、初始化高德地图:

1、xml布局引入:

2、地图AMap、MapView 相关配置

3、MapView的生命周期设置

4、实现定位功能:

1、初始化定位相关参数配置

2、定位信息的回调 

3、添加当前位置的Marker

5、打卡签到范围绘制

6、判断打卡签到是否在范围内


 效果图:

1、添加高德地图SDK到项目依赖中

     在项目的 build.gradle 文件中,添加以下依赖:

implementation 'com.amap.api:location:6.3.0'
implementation 'com.amap.api:navi-3dmap:7.4.0_3dmap7.4.0'

     在项目的 AndroidManifest.xml 文件中,添加如下:

<!--高德key-->
<meta-data
      android:name="com.amap.api.v2.apikey"
      android:value="申请的key" />

<!--高德定位服务-->
<service android:name="com.amap.api.location.APSService"/>

2、获取定位权限

     在项目的AndroidManifest.xml文件中,添加以下权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>  
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

    在Activity页面中,记得申请动态权限( sdk> 6.0)

3、初始化高德地图:

      1、xml布局引入:

          ps:TextureMapView或MapView都可以,我这里使用的TextureMapView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="44dp"
        android:background="#2c81ec">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="@color/white"
            android:textSize="18sp"
            android:text="打卡签到" />

    </RelativeLayout>

    <com.amap.api.maps.TextureMapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp">

        <TextView
            android:id="@+id/tv_cancel"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="返回"
            android:gravity="center"
            android:textSize="16sp"
            android:textColor="@color/white"
            android:background="#999999"/>

        <TextView
            android:id="@+id/tv_submit"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent"
            android:text="确认签到"
            android:gravity="center"
            android:textSize="16sp"
            android:textColor="@color/white"
            android:background="#2c81ec"/>

    </LinearLayout>


</LinearLayout>

    2、地图AMap、MapView 相关配置

    /**
     * 初始化 地图基础设置
     *
     * @param savedInstanceState
     */
    private void addMapViewSet(Bundle savedInstanceState) {
        // 显示地图
        mapView.onCreate(savedInstanceState);
        if (aMap == null) {
            aMap = mapView.getMap();//获取地图对象
        }
        //设置显示定位按钮 并且可以点击
        UiSettings uiSettings = aMap.getUiSettings();
        //设置定位监听:activate、deactivate
        aMap.setLocationSource(this);
        //缩放按钮隐藏(+ - )
        uiSettings.setZoomControlsEnabled(false);
        // TODO 自定义定位图标, 默认是蓝点
        aMap.setMyLocationStyle(addMyLocationStyle());
        // TODO 启动定位
        aMap.setMyLocationEnabled(true);
    }

    /**
     * 添加定位样式 (默认是蓝点)
     */
    private MyLocationStyle addMyLocationStyle() {
        MyLocationStyle locationStyle = new MyLocationStyle();
        locationStyle.myLocationIcon(BitmapDescriptorFactory.fromResource(R.mipmap.ic_seat_empty));
        locationStyle.showMyLocation(true);
        locationStyle.interval(4000);
        locationStyle.strokeColor(Color.argb(0, 0, 0, 0));
        locationStyle.radiusFillColor(Color.argb(0, 0, 0, 0));
        locationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER);//中心位置不旋转
        return locationStyle;
    }

3、MapView的生命周期设置

   @Override
    protected void onResume() {
        super.onResume();
        if (mapView != null)
            mapView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mapView != null)
            mapView.onPause();
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mapView != null)
            mapView.onSaveInstanceState(outState);
    }

    @Override
    protected void onDestroy() {
        if (mapView != null) {
            mapView.onDestroy();
        }
        if (mLocationClient != null) {
            mLocationClient.stopLocation();
            mLocationClient.onDestroy();
            mLocationClient=null;
        }
        super.onDestroy();
    }

4、实现定位功能:

     1、初始化定位相关参数配置

    /**
     * 初始化 定位配置
     */
    private void initLocationConfig() {
        try {
                //初始化定位
                mLocationClient = new AMapLocationClient(getApplicationContext());
                //设置定位回调监听
                mLocationClient.setLocationListener(this);
                //初始化定位参数
                mLocationOption = new AMapLocationClientOption();
                //设置定位模式为高精度模式,Battery_Saving为低功耗模式,Device_Sensors是仅设备模式
                mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
                //设置是否返回地址信息(默认返回地址信息)
                mLocationOption.setNeedAddress(true);
                //设置是否只定位一次,默认为false
                mLocationOption.setOnceLocation(false);
                mLocationOption.setHttpTimeOut(30000);
                //设置是否强制刷新WIFI,默认为强制刷新
                mLocationOption.setWifiActiveScan(true);
                //设置是否允许模拟位置,默认为false,不允许模拟位置
                mLocationOption.setMockEnable(false);
                //设置定位间隔,单位毫秒,默认为2000ms
                mLocationOption.setInterval(4000);
                //给定位客户端对象设置定位参数
                mLocationClient.setLocationOption(mLocationOption);
                //多次激活,最好调用一次stop,再调用start以保证场景模式生效
                //  mLocationClient.stopLocation();
               // 开始定位
                mLocationClient.startLocation();
        }catch (Exception e){
           //异常
        }
    }

2、定位信息的回调 

 AMapLocationListener类中,实现LocationSource接口,并重写onLocationChanged()方法,获取用户位置信息:

    @Override
    public void onLocationChanged(AMapLocation amapLocation) {
        if (amapLocation != null) {
            //定位成功回调信息
            if (amapLocation.getErrorCode() == 0) {
                mCurrentDetailedAddress = amapLocation.getAddress();
                if (isFirstLoc) {
                    //设置缩放级别17
                    aMap.moveCamera(CameraUpdateFactory.zoomTo(17));
                    //中心位置为当前坐标
                    aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude())));
                    mListener.onLocationChanged(amapLocation);
                    //添加电子围栏列表
                    drawCompanyFenceList();
                    isFirstLoc=false;
                }
                // 记录当前定位的坐标
                mCurrentLatLng = new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude());
                //添加当前位置的自定义图标
                addCurrentMarker(mCurrentLatLng, null, R.mipmap.ic_location_current);
                //重新移动到中心位置
                //aMap.moveCamera(CameraUpdateFactory.changeLatLng(new LatLng(amapLocation.getLatitude(), amapLocation.getLongitude())));
                Log.e("test-z", "----当前位置:"+amapLocation.getLatitude()+","+amapLocation.getLongitude()+" ,"+mCurrentDetailedAddress);
            } else {
                mCurrentLatLng = null;
            }
        }
    }

3、添加当前位置的Marker

    /**
     * TODO 当前位置的小图标
     *
     * @param latLng
     * @param object
     * @param icon  小图标
     */
    private void addCurrentMarker(LatLng latLng, Object object, int icon) {
        MarkerOptions markerOption = new MarkerOptions();
        markerOption.position(latLng);
        //设置Marker可拖动
        markerOption.draggable(false);
        markerOption.icon(BitmapDescriptorFactory.fromResource(icon));
        // 将Marker设置为贴地显示,可以双指下拉地图查看效果
        //设置marker平贴地图效果
        markerOption.setFlat(true);
        if (mCurrentMarker != null) {
            mCurrentMarker.remove();
        }
        mCurrentMarker = aMap.addMarker(markerOption);
        // marker.setObject(object);
    }

5、打卡签到范围绘制

     根据不同的图形进行绘制:

      1、如果是圆形,只需要一个中心经纬度、半径,传入 CircleOptions 并在Map图层添加;

      2、如果是多边形,将经纬度列表数据传入 PolygonOptions 并在Map图层添加即可

      3、如果业务的打卡范围定时变化,重新绘制之前,需要先将原来的清除,建议将添加后返回的对象进行存储,方便重新时清除,同时也可以直接使用该对象判断打卡点是否在范围内

    /**
     * 类型:圆
     *
     * @param centers 中心坐标
     * @param radius 半径
     */
    public void drawTypeCircle(List<PointBean> centers, double radius) {
        if(centers!=null && centers.size()>0){
            LatLng  centerLatLng=new LatLng(centers.get(0).getLatitude(), centers.get(0).getLongitude());
            //圆形
            CircleOptions circleOptions=new CircleOptions();
            //属性信息
            circleOptions.center(centerLatLng)
                    .center(centerLatLng)
                    .radius(radius) //半径范围
                    .strokeColor(Color.parseColor("#2c81ec"))
                    .strokeWidth(5)
                    .fillColor(Color.parseColor("#F772a7df"));
            Circle  circle = aMap.addCircle(circleOptions);
            //添加记录
            mAddFences.add(circle);
        }
    }
    
    /**
     * 类型:多边形
     * 提示:坐标需按照 顺时针或逆时针依次添加,否则会重叠
     *
     * @param points 经纬度集合
     */
    private void drawTypePolygon(List<PointBean> points) {
        if(points!=null && points.size()>0){
            List<LatLng> latLngList=new ArrayList<>();
            for(int i=0;i<points.size();i++){
                latLngList.add(new LatLng(points.get(i).getLatitude(), points.get(i).getLongitude()));
            }

            // 定义多边形的属性信息
            PolygonOptions polygonOptions = new PolygonOptions();
            polygonOptions.addAll(latLngList);
            // 设置多边形的边框颜色,32位 ARGB格式,默认为黑色
            polygonOptions.strokeColor(Color.parseColor("#2c81ec"));
            // 设置多边形的边框宽度,单位:像素
            polygonOptions.strokeWidth(4);
            // 设置多边形的填充颜色,32位ARGB格式
            polygonOptions.fillColor(Color.parseColor("#F772a7df"));
            Polygon polygon = aMap.addPolygon(polygonOptions);
            //添加记录
            mAddFences.add(polygon);
        }
    }

6、判断打卡签到是否在范围内

    在用户点击打卡时进行如下判断:

    for(int i=0;i<mAddFences.size();i++){
            if(mAddFences.get(i) instanceof Circle){
                Circle  circle= (Circle) mAddFences.get(i);
                if(circle.contains(mCurrentLatLng)){
                    return true;
                }
            }else if(mAddFences.get(i) instanceof Polygon){
                Polygon  polygon= (Polygon) mAddFences.get(i);
                if(polygon.contains(mCurrentLatLng)){
                    return true;
                }
            }
        }

最后,麻烦各位客官 点个赞 赞 赞

收藏+关注=下次不迷路

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/808068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IO流(1)-字符流与字节流

1. I/O流前置知识 在讲解IO流之前&#xff0c;需要先说明几个小知识点&#xff1a; &#xff08;1&#xff09;bit 是最小的二进制单位&#xff0c;是计算机的操作部分&#xff0c;取值0或1。 &#xff08;2&#xff09;Byte&#xff08;字节&#xff09;是计算机操作数据的…

PayPal:全球金融科技领域当之无愧的巨无霸

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 全球最大的金融科技公司之一PayPal(PYPL)将于2023年8月2日发布其2023年第二季度的财报。多年以来该公司一直在革新数字汇款和收款方式&#xff0c;并提高数百万客户的生活质量。此外&#xff0c;PayPal的各种工具也为企业…

Java文件操作与流处理

文章目录 一、文件1.1 文件的概念1.2 文件的组织结构1.3 绝对路径和相对路径 二、文件操作File类2.1 属性和常用方法2.2 使用案例 三、字节流和字符流3.1 InputStream 和 FileInputStream3.2 使用 Scanner 读取字符3.2 OutputStream 和 FileOutputStream3.3 Reader 和 FileRead…

【每日一题】141. 环形链表

【每日一题】141. 环形链表 【每日一题】141. 环形链表题目描述解题思路 【每日一题】141. 环形链表 题目描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环…

深入理解C++命名空间

文章目录 1. 命名空间的概念2. 解决命名冲突3. 嵌套命名空间4. 使用命名空间别名总结 在C编程中&#xff0c;命名空间&#xff08;Namespace&#xff09;是一种非常有用的工具&#xff0c;它可以帮助我们组织和管理代码&#xff0c;避免命名冲突。本文将深入介绍C命名空间的概念…

WIZnet W5500-EVB-Pico树莓派入门教程(一)

概述 W5500-EVB-Pico是基于树莓派RP2040和完全硬连线TCP/IP控制器W5500的微控制器开发板-基本上与树莓派Pico板相同&#xff0c;但通过W5500芯片增加了以太网功能。 板载资源 RP2040是Raspberry Pi的首款微控制器。它将我们的高性能、低成本和易用性的标志性价值观带入微控制器…

【Android安全】Embedded Trace Microcell模块

ETM: Embedded Trace Macrocell, hardware unit responsible to generate hardware instruction trace. ETM模块用于在硬件层面实现instruction trace&#xff0c;可用于辅助逆向分析。 使用教程&#xff1a; https://mcuoneclipse.com/2016/11/05/tutorial-getting-etm-inst…

如何集成 Milvus 和 LangChain?

以下代码集成了 Milvus 和 LangChain: class VectorStore(ABC):"""Interface for vector stores.""" @abstractmethoddef add_texts(self,texts: Iterable[str],metadatas: Optional[List[dict]] = None, kwargs:Any,) ->List[str]: &…

[STL]详解list模拟实现

[STL]list模拟实现 文章目录 [STL]list模拟实现1. 整体结构总览2. 成员变量解析3. 默认成员函数构造函数1迭代器区间构造函数拷贝构造函数赋值运算符重载析构函数 4. 迭代器及相关函数迭代器整体结构总览迭代器的模拟实现begin函数和end函数begin函数和end函数const版本 5. 数据…

Spring源码(四)— 创建BeanDefinition

在第一章序言的图示中有提到&#xff0c;Spring中的配置文件都是通过各种的BeanDefinition来进行解析&#xff0c;并且支持不同类型的文件进行扩展。所以在创建完DefaultListableBeanFactory后&#xff0c;会通过BeanDefinition来解析传入的xml配置文件。 loadBeanDefinitions…

如何建立ftp server?快解析内网穿透实现外网直接访问

serveru是一款由Rob Beckers开发的获奖的ftp服务器软件&#xff0c;全称为&#xff1a;serv-u ftp server&#xff0c;它功能强大又易于使用。ftp服务器用户通过它用ftp协议能在internet上共享文件。serv-u不仅100%遵从通用ftp标准&#xff0c;也包括众多的独特功能可为每个用户…

常用直线模组的类型

目前&#xff0c;直线模组的应用非常广泛&#xff0c;而且直线模组的种类也有很多可以满足每个行业的应用要求&#xff0c;那么常见的直线模组类型有哪些&#xff0c;大家知道吗&#xff1f; 1、全封闭滚珠丝杆直线模组&#xff1a; 在半封闭式的基础上增加了不锈钢带防尘结构…

自监督去噪: self2self 原理及实现(Pytorch)

Self2Self With Dropout: Learning Self-Supervised Denoising From Single Image 文章地址&#xff1a;https://ieeexplore.ieee.org/document/9157420原始代码&#xff1a;https://github.com/scut-mingqinchen/self2self本文参考代码: https://github.com/JinYize/self2self…

无线系统传输距离(天线收发功率计算)

无线通信系统如图8.1. 发射机发射功率,发射机天线增益; 接收机发射功率,接收机天线增益; 收发之间的距离是R; 如果没有大气损耗,极化失配,阻抗不匹配等情况,且天线在远场区域工作,那么各向同性发射天线在接收天线处的功率密度为 (8.1) 对于定向性天线,该公式修正…

No105.精选前端面试题,享受每天的挑战和学习

文章目录 手写new手写Mapget和post区别发起post请求的时候&#xff0c;服务端是怎么解析你的body的&#xff08;content-type&#xff09;&#xff0c;常见的content-type都有哪些&#xff0c;发文件是怎么解析的&#xff08;FormData&#xff09;&#xff0c;如果多个文件&…

微信小程序|进度条

进度条是一个常见的用户界面元素,用于显示任务或操作的完成进度,可以在任何需要指示任务进度的情况下使用,以提供更好的用户体验和反馈。 一、前言1.1 进度条使用场景1.2 进度条属性介绍1.3 示例代码及效果二、自定义进度条2.1 进度条形状2.2 进度条尺寸2.3 进度条条纹2.4 进…

【计算机网络】10、ethtool

文章目录 一、ethtool1.1 常见操作1.1.1 展示设备属性1.1.2 改变网卡属性1.1.2.1 Auto-negotiation1.1.2.2 Speed 1.1.3 展示网卡驱动设置1.1.4 只展示 Auto-negotiation, RX and TX1.1.5 展示统计1.1.7 排除网络故障1.1.8 通过网口的 LED 区分网卡1.1.9 持久化配置&#xff08…

GitHub仓库如何使用

核心&#xff1a;GitHub仓库如何使用 目录 1.创建仓库&#xff1a; 2.克隆仓库到本地&#xff1a; 3.添加、提交和推送更改&#xff1a; 4.分支管理&#xff1a; 5.拉取请求&#xff08;Pull Requests&#xff09;&#xff1a; 6.合并代码&#xff1a; 7.其他功能&…

windows 10/11 修改右键新建菜单

问题&#xff1a;修改右键新建菜单内容 解决方法&#xff1a;使用软件ShellNew Settings 1.打开软件 2.根据需要取消勾选项 3.最终效果

Linux 系列 常见 快捷键总结

强制停止 Ctrl C 退出程序、退出登录 Ctrl D 等价 exit 查看历史命令 history !命令前缀&#xff0c;自动匹配上一个命令 &#xff08;历史命令中&#xff1a;从最新——》最老 搜索&#xff09; ctrl r 输入内去历史命令中检索 # 回车键可以直接执行 ctrl a 跳到命令开头 …