HarmonyOS应用开辟:高德地图实现实时定位功能

打印 上一主题 下一主题

主题 964|帖子 964|积分 2892

效果图

卡片效果如下:







关键技术及实现原理

卡片现有支持的底子组件有:button、calendar、chart、clock、divider、image、input、progress、span、text。
可以看到现有的卡片组件并不支持地图的开辟,那么如何在卡片上显示地图尼?
通过 image 组件+高德地图 WebAPI 的静态地图即可实现地图的显示。
以上方便有开辟卡片履历的开辟者提供思绪,具体方式方法如下:
从零开始

①创建项目

打开 DevEco Studio 工具,点击 File->New->New Project 创建一个 Empty Ability(JS),如下图,SDK 选用了 API 5。

新建

参数调解
创建后的结构:

起首修改步伐的设置文件,打开 config.json,修改卡片支持类型环境:

添加权限:


设置完成还需要在 MainAbility 中显示的说明使用权限信息,详情参考文档设置相关内容。
打开 MainAbility 添加方法,并在 onStart 方法中调用 requestPermission();方法:
  1.   //获取权限
  2.     private void requestPermission() {
  3.         String[] permission = {
  4.                 "ohos.permission.LOCATION",
  5.                 "ohos.permission.LOCATION_IN_BACKGROUND",
  6.         };
  7.         List<String> applyPermissions = new ArrayList<>();
  8.         for (String element : permission) {
  9.             if (verifySelfPermission(element) != 0) {
  10.                 if (canRequestPermission(element)) {
  11.                     applyPermissions.add(element);
  12.                 }
  13.             }
  14.         }
  15.         requestPermissionsFromUser(applyPermissions.toArray(new String[0]), 0);
  16.     }
复制代码
②修改界面

打开 widget 下的 pages/index/imdex.hml:
  1. <div class="container">
  2.         <div class="container-inner" >
  3.             <div class="container-img">
  4.                 <stack>
  5.                     <image src="{{imgSrc}}" class="bg-img"></image>
  6.                     <div class="container-show-text" >
  7.                         <text class="show-text" >当前检索项:</text>
  8.                         <text class="show-text" style="color: coral;"  >{{searchText}}</text>
  9.                     </div>
  10.                     <div class="container-map-ctl">
  11.                         <button class="map-ctl-btn" @click="mapAddEvent"  type="circle">+</button>
  12.                         <button class="map-ctl-btn" @click="mapReduceEvent"  type="circle">-</button>
  13.                     </div>
  14.                     <div show="{{showCtlButton}}" class="container-ctl" >
  15.                         <button class="ctl-btn" @click="searchCheckedEvent0">{{searchBtns[0]}}</button>
  16.                         <button class="ctl-btn" @click="searchCheckedEvent1">{{searchBtns[1]}}</button>
  17.                         <button class="ctl-btn" @click="searchCheckedEvent2">{{searchBtns[2]}}</button>
  18.                         <button class="ctl-btn" @click="searchCheckedEvent3">{{searchBtns[3]}}</button>
  19.                         <button class="ctl-btn" @click="searchCheckedEvent4">{{searchBtns[4]}}</button>
  20.                     </div>
  21.                 </stack>
  22.             </div>
  23.         </div>
  24. </div>
复制代码
需要注意:卡片的事件不能使用表达式,不能使用 for 语句循环构建。
样式调解文件 pages/index/imdex.css:
  1. .container {
  2.     flex-direction: column;
  3.     justify-content: center;
  4.     align-items: center;
  5. }
  6. .bg-img {
  7.     flex-shrink: 0;
  8.     height: 100%;
  9.     object-fit: cover;
  10. }
  11. .container-ctl{
  12.     opacity: 0.9;
  13.     width: 100%;
  14.     height: 100%;
  15.     justify-content: center;
  16.     flex-direction: row;
  17.     align-items: flex-end;
  18.     bottom: 3px;
  19. }
  20. .ctl-btn{
  21.     padding: 3px 6px;
  22.     margin:3px 6px;
  23.     font-size: 12px;
  24.     border-radius: 3px;
  25.     background-color: #409eff;
  26.     border: 1px solid #cbcbcb;
  27.     box-shadow: 1px 1px 3px #a8a8a8;
  28. }
  29. .container-map-ctl{
  30.     opacity: 0.8;
  31.     justify-content: flex-end;
  32.     margin-right: 3px;
  33. }
  34. .map-ctl-btn{
  35.     background-color: #409eff;
  36.     border: 1px solid #cbcbcb;
  37.     box-shadow: 1px 1px 3px #a8a8a8;
  38.     width: 24px;
  39.     height: 24px;
  40.     margin:3px;
  41. }
  42. .container-show-text{
  43.     padding: 9px;
  44. }
  45. .show-text{
  46.     font-size: 8px;
  47.     font-weight: bolder;
  48. }
复制代码
json 设置信息修改 pages/index/index.json:
  1. {
  2.   "data": {
  3.     "showCtlButton": false,//是否显示button。由Java传值且在2x2的界面不显示
  4.     "imgSrc": "/common/ic_default_image@3x.png",//默认图片
  5.     "searchText": "",
  6.     "searchBtns": []//配置的button按钮信息
  7.   },
  8.   "actions": {
  9.     "searchCheckedEvent0": {
  10.       "action": "message",
  11.       "params": {
  12.         "index": 0,
  13.         "name": "checkSearch"
  14.       }
  15.     },
  16.     "searchCheckedEvent1": {
  17.       "action": "message",
  18.       "params": {
  19.         "index": 1,
  20.         "name": "checkSearch"
  21.       }
  22.     },
  23.     "searchCheckedEvent2": {
  24.       "action": "message",
  25.       "params": {
  26.         "index": 2,
  27.         "name": "checkSearch"
  28.       }
  29.     },
  30.     "searchCheckedEvent3": {
  31.       "action": "message",
  32.       "params": {
  33.         "index": 3,
  34.         "name": "checkSearch"
  35.       }
  36.     },
  37.     "searchCheckedEvent4": {
  38.       "action": "message",
  39.       "params": {
  40.         "index": 4,
  41.         "name": "checkSearch"
  42.       }
  43.     },
  44.     "mapAddEvent": {
  45.       "action": "message",
  46.       "params": {
  47.         "name": "mapAdd"
  48.       }
  49.     },
  50.     "mapReduceEvent": {
  51.       "action": "message",
  52.       "params": {
  53.         "name": "mapReduce"
  54.       }
  55.     }
  56.   }
  57. }
复制代码
后台逻辑

由于更新卡片时需要提供 formId,我们对 FormController 及 FormControllerManager 这两个帮助类举行一个修改。
打开 java 目录下的 FormController 文件并添加受保护的属性 formId,并修改构造函数。

然后进入 FormControllerManager 找到 createFormController、getController、newInstance 举行修改。
①createFormController

在 newInstance 方法中添加参数 formId,如下图:

②getController

在 newInstance 方法中添加参数 formId,如下图:

③newInstace

该方法是动态的创建 WidgetImpl 方法,类似于 IOC 作用:

找到 java 目录下的 widget/widget/widgetImpl,卡片的全部逻辑都在该文件内。
起首修改构造函数及定义底子属性等,因上述修改了 FormController 及 FormControllerManager 构造函数必须增加 Long formId 参数。
  1.     private static Location slocation=null;//当前位置信息
  2.     private Boolean slocationChanged=false;//位置是否修改
  3.     private  int dimension=2;//当前卡片模式  2x2=2;2x4=3;4x4=4;
  4.     private List<String> defualtBtn=new ArrayList<>();//界面下方的按钮列表
  5.     private static Locator locator=null;//坐标获取类
  6.     private LocatorCallBack locatorCallBack=new LocatorCallBack();//坐标获取后返回调用类
  7.     private int mRoom=16;//静态地图显示层级
  8.     private String markType="";//静态地图周边搜索关键字
  9.     private String mSize="500*500";//静态地图大小
  10.     private List<String> mKeyLocation=new ArrayList<>();//静态地图获取周边标记的坐标
  11.     RequestParam requestParam = new RequestParam(RequestParam.PRIORITY_ACCURACY, 20, 0);
  12.     public WidgetImpl(Context context, String formName, Integer dimension,Long formId) {
  13.         super(context, formName, dimension,formId);
  14.         this.dimension=dimension;
  15.         //获取当前定位
  16.         if(locator==null){
  17.             locator=new Locator(context);
  18.             locator.startLocating(requestParam,locatorCallBack);
  19.         }
  20.         switch (dimension){
  21.             case 2:{
  22.                 mSize="300*300";
  23.                 mRoom=13;
  24.                 break;
  25.             }
  26.             case 3:{
  27.               mSize="500*250";
  28.               mRoom=13;
  29.               break;
  30.             }
  31.             case 4:{
  32.                 mSize="500*500";
  33.                 mRoom=15;
  34.                 break;
  35.             }
  36.         }
  37.     }
  38.     public class LocatorCallBack implements LocatorCallback{
  39.         @Override
  40.         public void onLocationReport(Location location) {
  41.             slocation=location;
  42.             //周边信息接口额度有限,限制为当坐标改变时刷新坐标mark信息,并更新卡片
  43.             if(location==slocation || slocation==null)
  44.                 return;
  45.             refreshMark();
  46.             updateFormData(formId);
  47.         }
  48.         @Override
  49.         public void onStatusChanged(int i) {
  50.         }
  51.         @Override
  52.         public void onErrorReport(int i) {
  53.         }
  54.     }
复制代码
修改 createFormController,该方法在卡片创建时调用,我们需要把页面需要的参数传递已往。
注意网络图片需要使用“通过内存图片方式使用 image 组件。
  1.    @Override
  2.     public ProviderFormInfo bindFormData(){
  3.         defualtBtn=new ArrayList<>();
  4.         defualtBtn.add("酒店");
  5.         defualtBtn.add("餐饮");
  6.         defualtBtn.add("景点");
  7.         defualtBtn.add("加油站");
  8.         if(defualtBtn.size()<5){
  9.             for(int i=defualtBtn.size();i<5;i++){
  10.                 defualtBtn.add("未设置");
  11.             }
  12.         }
  13.         this.markType=defualtBtn.get(0);
  14.         this.refreshMark();
  15.         FormBindingData formBindingData=null;
  16.         ZSONObject zsonObject =new ZSONObject();
  17.         zsonObject.put("imgSrc","memory://amap.png");
  18.         zsonObject.put("showCtlButton",this.dimension!=2);
  19.         zsonObject.put("searchBtns",defualtBtn);
  20.         zsonObject.put("searchText",markType);
  21.         formBindingData=new FormBindingData(zsonObject);
  22.         ProviderFormInfo formInfo = new ProviderFormInfo();
  23.         formInfo.setJsBindingData(formBindingData);
  24.         String amapUrl=getMapImageUrl(mKeyLocation);
  25.         byte[] bytes= HttpImageUtils.doGetRequestForFile(amapUrl);
  26.         formBindingData.addImageData("amap.png",bytes);
  27.         return formInfo;
  28.     }
复制代码
初始化卡片后改进 onTriggerFormEvent,该方法为接收卡片事件,message 为事件传递的 params 参数。
  1.     @Override
  2.     public void onTriggerFormEvent(long formId, String message) {
  3.         ZSONObject request=ZSONObject.stringToZSON(message);
  4.         String EventName=request.getString("name");
  5.         switch (EventName){
  6.             case "checkSearch":{
  7.                 int index=request.getIntValue("index");
  8.                 markType=defualtBtn.get(index);
  9.                 this.refreshMark();
  10.                 break;
  11.             }
  12.             case "mapAdd":{
  13.                 if(mRoom<17){
  14.                     mRoom+=1;
  15.                 }
  16.                 break;
  17.             }
  18.             case "mapReduce":{
  19.                 if(mRoom>0){
  20.                     mRoom-=1;
  21.                 }
  22.                 break;
  23.             }
  24.         }
  25.         updateFormData(formId);
  26.     }
复制代码
修改更新卡片信息的方法,此方法不仅是体系会定时刷新,也有主动刷新的调用如:卡片事件改变后调用,坐标改变后的调用。
这也是需要修改 FormController、FormControllerManager 增加 formId 属性的缘故起因,因为在主动刷新时需要 formId 参数。
此处另有一个重点就是:
  1.   ((Ability)context).updateForm(formId,bindingData);
复制代码
  1.     @Override    public void updateFormData(long formId, Object... vars) {        ZSONObject zsonObject=new ZSONObject();        zsonObject.put("searchBtns",defualtBtn);        zsonObject.put("searchText",markType);        String mapName="amap"+System.currentTimeMillis()+".png";        zsonObject.put("imgSrc","memory://"+mapName);        FormBindingData bindingData = new FormBindingData(zsonObject);        String amapUrl=getMapImageUrl(mKeyLocation);        byte[] bytes= HttpImageUtils.doGetRequestForFile(amapUrl);        bindingData.addImageData(mapName,bytes);        try{            ((Ability)context).updateForm(formId,bindingData);
  2.         }catch (Exception ex){            ex.printStackTrace();        }    }
复制代码
其他一些上述方法中调用的私有方法及类。
私有方法:
  1.     private void refreshMark(){
  2.         try{
  3.             this.mKeyLocation= HttpImageUtils.SearchByKeyUrl(getMapMarkUrl(10));
  4.         }catch (Exception ex){
  5.             ex.printStackTrace();
  6.         }
  7.     }
  8.     private String getMapImageUrl(List<String> Position){
  9.         String url="https://restapi.amap.com/v3/staticmap";
  10.         String params="key=";
  11.         params+="&zoom="+mRoom;
  12.         params+="&size="+mSize;
  13.         if(slocation!=null)
  14.             params+="&location="+slocation.getLongitude()+","+slocation.getLatitude();
  15.         params+="&markers=large,0xea7700,H:"+slocation.getLongitude()+","+slocation.getLatitude();
  16.         if(Position==null || Position.size()==0)
  17.             return  url+"?"+params;
  18.         String markers="|mid,0xFF0000,:";
  19.         for(int i=0;i<Position.size();i++){
  20.             markers+=Position.get(i)+";";
  21.         }
  22.         params+=markers.substring(0,markers.length()-1);
  23.         return url+"?"+params;
  24.     }
  25.     private  String getMapMarkUrl(int size){
  26.         String Url="https://restapi.amap.com/v5/place/around?key=";
  27.         Url+="&keywords="+(markType=="未设置"?"":markType);
  28.         if(slocation!=null)
  29.             Url+="&location="+slocation.getLongitude()+","+slocation.getLatitude();
  30.         Url+="&size="+size;
  31.         return Url;
  32.     }
复制代码
HttpImageUtils 类:
  1. package com.panda_coder.amapcard.utils;
  2. import com.panda_coder.amapcard.MainAbility;
  3. import ohos.hiviewdfx.HiLog;
  4. import ohos.hiviewdfx.HiLogLabel;
  5. import ohos.utils.zson.ZSONArray;
  6. import ohos.utils.zson.ZSONObject;
  7. import java.io.*;
  8. import java.net.HttpURLConnection;
  9. import java.net.URL;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12. public class HttpImageUtils {
  13.     private static final HiLogLabel TAG = new HiLogLabel(HiLog.DEBUG, 0x0, MainAbility.class.getName());
  14.     public final static byte[] doGetRequestForFile(String urlStr) {
  15.         InputStream is = null;
  16.         HttpURLConnection conn = null;
  17.         byte[] buff = new byte[1024];
  18.         try {
  19.             URL url = new URL(urlStr);
  20.             conn = (HttpURLConnection) url.openConnection();
  21.             conn.setDoInput(true);
  22.             conn.setRequestMethod("GET");
  23.             conn.setReadTimeout(6000);
  24.             conn.connect();
  25.             is = conn.getInputStream();
  26.             if (conn.getResponseCode() == 200) {
  27.                 buff = readInputStream(is);
  28.             } else{
  29.                 buff=null;
  30.             }
  31.         } catch (Exception e) {
  32.             HiLog.error(TAG,"【获取图片异常】",e);
  33.         }
  34.         finally {
  35.             try {
  36.                 if(is != null){
  37.                     is.close();
  38.                 }
  39.             } catch (IOException e) {
  40.                 e.printStackTrace();
  41.             }
  42.             conn.disconnect();
  43.         }
  44.         return buff;
  45.     }
  46.     public static byte[] readInputStream(InputStream is) {
  47.         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  48.         byte[] buffer = new byte[1024];
  49.         int length = -1;
  50.         try {
  51.             while ((length = is.read(buffer)) != -1) {
  52.                 baos.write(buffer, 0, length);
  53.             }
  54.             baos.flush();
  55.         } catch (IOException e) {
  56.             e.printStackTrace();
  57.         }
  58.         byte[] data = baos.toByteArray();
  59.         try {
  60.             is.close();
  61.             baos.close();
  62.         } catch (IOException e) {
  63.             e.printStackTrace();
  64.         }
  65.         return data;
  66.     }
  67.     public static String httpGet(String urlStr){
  68.         InputStream is = null;
  69.         HttpURLConnection conn = null;
  70.         String response="";
  71.         StringBuffer buffer = new StringBuffer();
  72.         try {
  73.             URL url = new URL(urlStr);
  74.             conn = (HttpURLConnection) url.openConnection();
  75.             conn.setDoInput(true);
  76.             conn.setRequestMethod("GET");
  77.             conn.setReadTimeout(6000);
  78.             conn.connect();
  79.             is = conn.getInputStream();
  80.             if (conn.getResponseCode() == 200) {
  81.                 String str=null;
  82.                 InputStreamReader isr = new InputStreamReader(is,"utf-8");
  83.                 BufferedReader br = new BufferedReader(isr);
  84.                 while((response = br.readLine())!=null){
  85.                     buffer.append(response);
  86.                 }
  87.             }
  88.             response=buffer.toString();
  89.         } catch (Exception e) {
  90.             HiLog.error(TAG,"【访问异常】",e);
  91.         }
  92.         finally {
  93.             try {
  94.                 if(is != null){
  95.                     is.close();
  96.                 }
  97.             } catch (IOException e) {
  98.                 e.printStackTrace();
  99.             }
  100.             conn.disconnect();
  101.         }
  102.         return response;
  103.     }
  104.     public final  static List<String> SearchByKeyUrl(String urlStr){
  105.         List<String> result=new ArrayList<>();
  106.         String response= httpGet(urlStr);
  107.         if(response==null || response=="")
  108.             return result;
  109.         ZSONObject zson=ZSONObject.stringToZSON(response);
  110.         if(zson.getIntValue("infocode")!=10000)
  111.             return result;
  112.         ZSONArray zsonArray=zson.getZSONArray("pois");
  113.         for(int i=0;i<zsonArray.size();i++){
  114.             ZSONObject child= (ZSONObject)zsonArray.get(i);
  115.             String location=child.getString("location");
  116.             result.add(location);
  117.         }
  118.         return result;
  119.     }
  120. }
复制代码
至此一个地图周边的卡片即可开辟完成
最后

有许多小伙伴不知道学习哪些鸿蒙开辟技术?不知道需要重点掌握哪些鸿蒙应用开辟知识点?但是又不知道从那里动手,而且学习时频仍踩坑,最终浪费大量时间。所以本人整理了一些比力合适的鸿蒙(HarmonyOS NEXT)学习路径和一些资料的整理供小伙伴学习
点击领取→纯血鸿蒙Next全套最新学习资料希望这一份鸿蒙学习资料可以大概给大家带来帮助,有需要的小伙伴自行领取~~
一、鸿蒙(HarmonyOS NEXT)最新学习蹊径
​​
有了蹊径图,怎么能没有学习资料呢,小编也预备了一份团结鸿蒙官方发布条记整理收纳的一套体系性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开辟入门讲授视频,内容包含:(ArkTS、ArkUI开辟组件、Stage模子、多端部署、分布式应用开辟、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开辟、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)…等技术知识点。
获取以上完备版高清,请点击→纯血版全套鸿蒙HarmonyOS学习资料
二、HarmonyOS Next 最新全套视频教程
​​

三、《鸿蒙 (OpenHarmony)开辟底子到实战手册》
OpenHarmony北向、南向开辟环境搭建
​​
四、大厂面试必问面试题
​​
五、鸿蒙南向开辟技术
​​
六、鸿蒙APP开辟必备
​​
完备鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,对于大家来说ye是一个挑衅,也是一个机会。只有积极应对变化,不绝学习和提升本身,他们才气在这个厘革的时代中立于不败之地。 

                        




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

缠丝猫

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表