ArcGIS for Android 自定義地圖比例尺

来源:http://www.cnblogs.com/yihoudangxian/archive/2017/11/02/7772500.html
-Advertisement-
Play Games

在我們進行地圖相關開發時候,避免不了要繪製比例尺。在百度,高德的地圖API里都提供了比例尺控制項,但是ArcGIS for Android里並沒有提供。不過沒關係,我們可以自己繪製一個比例尺來。 在繪製比例尺前,我們先瞭解幾個概念: 其中PPI和DPI在實際生活中的定義是不太一樣的,而在Android ...


在我們進行地圖相關開發時候,避免不了要繪製比例尺。在百度,高德的地圖API里都提供了比例尺控制項,但是ArcGIS for Android里並沒有提供。不過沒關係,我們可以自己繪製一個比例尺來。

 

      在繪製比例尺前,我們先瞭解幾個概念:

 

 

  1. PPI,Pixels Per Inch的所寫,表示的是每英寸所擁有的像素數目;
  2. PX,像素,表示圖像中的一個最小單位;
  3. DPI,Dots Per Inch,每英寸點數,即圖像密度;
  4. .9.PNG,Android開發裡面的一種特殊的圖片,這種格式的圖片通過ADT自帶的編輯工具生成,使用九宮格切分的方法,使圖片支持在Android環境下的自適應展示。即這種類型圖片在Android里無論怎樣拉伸縮小都不失真。

 

 

      其中PPI和DPI在實際生活中的定義是不太一樣的,而在Android里,他們的含義卻是相似的。單獨把DPI拿出來主要是Android里有個方法可以分別獲取到屏幕X軸和Y軸的像素密度。

 

      .9.PNG格式的圖片不失真,正好適合我們做來做比例尺圖片。

 

       好了,我們好繪製一個比例尺,需要做些什麼呢?

 

       首先,我們得知道當前地圖比例,這個參數可以通過MapView.getScale來獲取;

 

       其次,我們要根據當前地圖比例繪製一個比例尺。繪製的方案有兩種,一個是固定尺子長度,根據當前地圖比例更換比例尺的比,比如1:2000,1:3000等;另一種是固定一些比例單位,比如1:50000後就是1:20000,然後比例尺的長度根據實際長度會做一定伸縮。這裡我採用第二種,因為第一種根據實際比例往往比例尺的比值不是整數,並且在較大比例時候顯示位數較長,四捨五入又會失去精度。

 

      最後,是監聽地圖放大縮小事件,並作出響應改變比例尺。

 

      方法就是這麼簡單,那就實際開動吧。

 

第一步,實例化地圖,載入圖層:

 

[java] view plain copy  
  1. mMapView=(MapView)findViewById(R.id.mapview);  
  2. mMapScaleView=(MapScaleView)findViewById(R.id.scaleView);  
  3. String path= StorageUtil.getSDCardRootPath(getApplicationContext());  
  4. ArcGISLocalTiledLayer layer=new ArcGISLocalTiledLayer(path);  
  5. mMapView.addLayer(layer,0);  
  6. mMapScaleView.setMapView(mMapView);  
  7. ArcGISRuntime.setClientId(System.clint);//設置許可  
  8. mMapView.setMapBackground(0xFAFAFA, 0xffffff, 0.0f, 0.0f);//地圖背景  

 

 

第二步,自定義View,繪製比例尺:

      

      初始化自定義View:

 

[java] view plain copy  
  1. public MapScaleView(Context context) {  
  2.     this(context, null);  
  3.     this.context=context;  
  4.     this.initVariables();  
  5. }  
  6.   
  7. public MapScaleView(Context context, AttributeSet attrs) {  
  8.     this(context, attrs, 0);  
  9.     this.context=context;  
  10.     this.initVariables();  
  11. }  
  12.   
  13. public MapScaleView(Context context, AttributeSet attrs, int defStyle) {  
  14.     super(context, attrs, defStyle);  
  15.     this.context=context;  
  16.     this.initVariables();  
  17. }  

 

 

      初始化自定義View的參數:

 

[java] view plain copy  
  1. private void initVariables(){  
  2.     scaleWidth=104;//  
  3.     scaleHeight=8;//比比例尺寬度例尺高度  
  4.     textColor= Color.BLACK;//比例尺字體顏色  
  5.     text="20公裡";//比例尺文本  
  6.     textSize=18;//比例尺寬度  
  7.     scaleSpaceText=8;//比例尺文本與圖形的間隔高度  
  8.     mPaint = new Paint();//畫筆  
  9. }  

 

 

      重寫onMearsure()方法:

 

[java] view plain copy  
  1. @Override  
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  3.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  4.     int widthSize = getWidthSize(widthMeasureSpec);  
  5.     int heightSize = getHeightSize(heightMeasureSpec);  
  6.     setMeasuredDimension(widthSize, heightSize);  
  7. }  

 

 

      獲取自定義View的寬和高:

 

[java] view plain copy  
  1. **  
  2.  * 測量ScaleView的寬度  
  3.  * @param widthMeasureSpec  
  4.  * @return  
  5.  */  
  6. private int getWidthSize(int widthMeasureSpec){  
  7.     return MeasureSpec.getSize(widthMeasureSpec);  
  8. }  
  9.   
  10. /** 
  11.  * 測量ScaleView的高度 
  12.  * @param heightMeasureSpec 
  13.  * @return 
  14.  */  
  15. private int getHeightSize(int heightMeasureSpec){  
  16.     int mode = MeasureSpec.getMode(heightMeasureSpec);  
  17.     int height = 0;  
  18.     switch (mode) {  
  19.         case MeasureSpec.AT_MOST:  
  20.             height = textSize + scaleSpaceText + scaleHeight;  
  21.             break;  
  22.         case MeasureSpec.EXACTLY:{  
  23.             height = MeasureSpec.getSize(heightMeasureSpec);  
  24.             break;  
  25.         }  
  26.         case MeasureSpec.UNSPECIFIED:{  
  27.             height = Math.max(textSize + scaleSpaceText + scaleHeight, MeasureSpec.getSize(heightMeasureSpec));  
  28.             break;  
  29.         }  
  30.     }  
  31.   
  32.     return height;  
  33. }  

 

 

      重寫onDraw()方法,繪製比例尺:

 

[java] view plain copy  
  1. **  
  2.  * 繪製上面的文字和下麵的比例尺,因為比例尺是.9.png,我們需要利用drawNinepath方法繪製比例尺  
  3.  */  
  4. @SuppressLint("DrawAllocation")  
  5. @Override  
  6. protected void onDraw(Canvas canvas) {  
  7.     super.onDraw(canvas);  
  8.     int width = scaleWidth ;  
  9.     mPaint.setColor(textColor);  
  10.     mPaint.setAntiAlias(true);  
  11.     mPaint.setTextSize(textSize);  
  12.     mPaint.setTypeface(Typeface.DEFAULT_BOLD);  
  13.     float textWidth = mPaint.measureText(text);  
  14.     canvas.drawText(text, (width - textWidth) / 2, textSize, mPaint);  
  15.     Rect scaleRect = new Rect(0, textSize + scaleSpaceText, width, textSize + scaleSpaceText + scaleHeight);  
  16.     drawNinepath(canvas, R.drawable.icon_scale, scaleRect);  
  17. }  

 

 

      繪製.9.PNG圖片:

 

[java] view plain copy  
  1. private void drawNinepath(Canvas canvas, int resId, Rect rect){  
  2.     Bitmap bmp= BitmapFactory.decodeResource(getResources(), resId);  
  3.     NinePatch patch = new NinePatch(bmp, bmp.getNinePatchChunk(), null);  
  4.     patch.draw(canvas, rect);  
  5. }  

 

 

      接下來就是根據獲取的地圖比例,繪製比例尺,更新比例尺的單位以及繪製它的長度,這裡我按照2、5、1的進位選取了比例尺的單位:

 

[java] view plain copy  
  1. /** 
  2.  * 根據縮放級別更新ScaleView的文字以及比例尺的長度 
  3.  */  
  4. public void refreshScaleView() {  
  5.     if(mapView == null){  
  6.         throw new NullPointerException("you can call setMapView(MapView mapView) at first");  
  7.     }  
  8.     double scale=this.mapView.getScale()/100;//結果單位米,表示圖上1釐米代表*米  
  9.     double ppi=getPPIOfDevice();  
  10.     if(scale>0&&scale<=20){//換算20米  
  11.         String unit = "20米";  
  12.         int scaleWidth=(int)(20*ppi/2.54/scale);//ppi為每英尺像素數,ppi/2.54為1釐米的像素數  
  13.         setText(unit);//更新文字  
  14.         setScaleWidth(scaleWidth);//更新比例尺長度  
  15.     }else if(scale>20&&scale<=50){//換算50米  
  16.         String unit = "50米";  
  17.         int scaleWidth=(int)(50*ppi/2.54/scale);  
  18.         setText(unit);//更新文字  
  19.         setScaleWidth(scaleWidth);//更新比例尺長度  
  20.     }else if(scale>50&&scale<=100){//換算20米  
  21.         String unit = "100米";  
  22.         int scaleWidth=(int)(100*ppi/2.54/scale);  
  23.         setText(unit);//更新文字  
  24.         setScaleWidth(scaleWidth);//更新比例尺長度  
  25.     }else if(scale>100&&scale<=200){//換算20米  
  26.         String unit = "200米";  
  27.         int scaleWidth=(int)(200*ppi/2.54/scale);  
  28.         setText(unit);//更新文字  
  29.         setScaleWidth(scaleWidth);//更新比例尺長度  
  30.     }else if(scale>200&&scale<=500){//換算20米  
  31.         String unit = "500米";  
  32.         int scaleWidth=(int)(500*ppi/2.54/scale);  
  33.         setText(unit);//更新文字  
  34.         setScaleWidth(scaleWidth);//更新比例尺長度  
  35.     }else if(scale>500&&scale<=1000){//換算20米  
  36.         String unit = "1公裡";  
  37.         int scaleWidth=(int)(1000*ppi/2.54/scale);  
  38.         setText(unit);//更新文字  
  39.         setScaleWidth(scaleWidth);//更新比例尺長度  
  40.     }else if(scale>1000&&scale<=2000){//換算20米  
  41.         String unit = "2公裡";  
  42.         int scaleWidth=(int)(2000*ppi/2.54/scale);  
  43.         setText(unit);//更新文字  
  44.         setScaleWidth(scaleWidth);//更新比例尺長度  
  45.     }else if(scale>2000&&scale<=5000){//換算20米  
  46.         String unit = "5公裡";  
  47.         int scaleWidth=(int)(5000*ppi/2.54/scale);  
  48.         setText(unit);//更新文字  
  49.         setScaleWidth(scaleWidth);//更新比例尺長度  
  50.     }else if(scale>5000&&scale<=10000){//換算20米  
  51.         String unit = "10公裡";  
  52.         int scaleWidth=(int)(10000*ppi/2.54/scale);  
  53.         setText(unit);//更新文字  
  54.         setScaleWidth(scaleWidth);//更新比例尺長度  
  55.     }else if(scale>10000&&scale<=20000){//換算20米  
  56.         String unit = "20公裡";  
  57.         int scaleWidth=(int)(20000*ppi/2.54/scale);  
  58.         setText(unit);//更新文字  
  59.         setScaleWidth(scaleWidth);//更新比例尺長度  
  60.     }else if(scale>20000&&scale<=25000){//換算20米  
  61.         String unit = "25公裡";  
  62.         int scaleWidth=(int)(25000*ppi/2.54/scale);  
  63.         setText(unit);//更新文字  
  64.         setScaleWidth(scaleWidth);//更新比例尺長度  
  65.     }else if(scale>25000&&scale<=50000){//換算20米  
  66.         String unit = "50公裡";  
  67.         int scaleWidth=(int)(50000*ppi/2.54/scale);  
  68.         setText(unit);//更新文字  
  69.         setScaleWidth(scaleWidth);//更新比例尺長度  
  70.     }else if(scale>50000&&scale<=100000){//換算20米  
  71.         String unit = "100公裡";  
  72.         int scaleWidth=(int)(100000*ppi/2.54/scale);  
  73.         setText(unit);//更新文字  
  74.         setScaleWidth(scaleWidth);//更新比例尺長度  
  75.     }else if(scale>100000&&scale<=200000){//換算20米  
  76.         String unit = "200公裡";  
  77.         int scaleWidth=(int)(200000*ppi/2.54/scale);  
  78.         setText(unit);//更新文字  
  79.         setScaleWidth(scaleWidth);//更新比例尺長度  
  80.     }else if(scale>200000&&scale<=250000){//換算20米  
  81.         String unit = "250公裡";  
  82.         int scaleWidth=(int)(250000*ppi/2.54/scale);  
  83.         setText(unit);//更新文字  
  84.         setScaleWidth(scaleWidth);//更新比例尺長度  
  85.     }else if(scale>250000&&scale<=500000){//換算20米  
  86.         String unit = "500公裡";  
  87.         int scaleWidth=(int)(500000*ppi/2.54/scale);  
  88.         setText(unit);//更新文字  
  89.         setScaleWidth(scaleWidth);//更新比例尺長度  
  90.     }else if(scale>500000&&scale<=1000000){//換算20米  
  91.         String unit = "1000公裡";  
  92.         int scaleWidth=(int)(1000000*ppi/2.54/scale);  
  93.         setText(unit);//更新文字  
  94.         setScaleWidth(scaleWidth);//更新比例尺長度  
  95.     }  
  96.   
  97.     invalidate();  
  98. }  

 

 

      其中,獲取屏幕PPI的方法如下:首先是用android.view包下的Display類里的getRealSize()方法獲取屏幕解析度;其次是用android.util包下有個DisplayMetrics類來獲取密度相關的信息,該類里的xdpi和ydpi參數分別表示屏幕X軸和Y軸的點數密度,用X軸和Y軸的像素除以密度得到X軸和Y軸的真實長度,進而求得屏幕對角線的真實長度;最後用屏幕對角線的像素點數除以屏幕對角線的真實長度,得到屏幕的PPI:

 

[java] view plain copy  
  1. private double getPPIOfDevice() {  
  2.     Point point = new Point();  
  3.     Activity activity=(Activity) context;  
  4.     activity.getWindowManager().getDefaultDisplay().getRealSize(point);//獲取屏幕的真實解析度  
  5.     DisplayMetrics dm = getResources().getDisplayMetrics();  
  6.     double x = Math.pow(point.x/ dm.xdpi, 2);//  
  7.     double y = Math.pow(point.y / dm.ydpi, 2);  
  8.     double screenInches = Math.sqrt(x + y);  
  9.     Double ppi=Math.sqrt(Math.pow(point.x, 2)+Math.pow(point.y, 2))/screenInches;  
  10.     return ppi;  
  11. }  

 源碼免費下載地址:http://www.jinhusns.com/Products/Download


第三步:寫響應事件

 

 

      在ArcGIS的MapView有個監聽地圖大小變化的方法,叫setOnZoomListener(),在裡面寫響應事件即可:

 

[java] view plain copy  
  1. mMapView.setOnZoomListener(new OnZoomListener() {  
  2.     @Override  
  3.     public void preAction(float v, float v1, double v2) {  
  4.         //todo  
  5.     }  
  6.   
  7.     @Override  
  8.     public void postAction(float v, float v1, double v2) {  
  9.         mMapScaleView.refreshScaleView();  
  10.     }  
  11. });  

 


      效果圖如下:

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 其中最後一個參數'sysdate+1/1440'表示時間間隔為每分鐘。其它常用的時間間隔的設置如下: (1)如果想每天凌晨1點執行,則此參數可設置為'trunc(sysdate)+25/24'; (2)如果想每周一凌晨1點執行,則此參數可設置為'trunc(next_day(sysdate,1))+ ...
  • 世上豈無千里馬,人中難得九方皋; 酒船魚網歸來是,花落故溪深一篙。 關於資料庫的第一篇博客,這是我的第二次,人生第二春,什麼也不想說,靜靜的開始吧,至於為什麼寫唐詩,請看第一篇文章! Oracle 初級(一) 同學去面試被問到了一個問題:DML 語句指什麼,當時同學一臉懵圈的看著面試官,最後微微一笑 ...
  • 這裡對於App在微信開放平臺上申請AppID和secret在這裡就略過了,我們微信的授權登錄流程,騰訊官網給的流程如下: 1. 第三方發起微信授權登錄請求,微信用戶允許授權第三方應用後,微信會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code參數; 2. 通過code參數加上AppID和Ap ...
  • 地推是推廣app的一種重要手段,同時地推結算對地推統計的精度的要求非常高,而openinstall就是一款符合要求的地推統計結算工具。它不僅多渠道統計能力強,安裝設備識別精準,渠道統計精度高。還支持地推人員單獨查看所負責渠道的實時統計數據,避免統計數據爭議,同時讓也讓推廣人員實時瞭解自己的推廣狀態,... ...
  • 一,效果圖。 二,工程圖。 三, 代碼。 ViewController.h #import <UIKit/UIKit.h> //loading #import "GPLoadingButton.h" @interface ViewController : UIViewController { //l ...
  • 最正規的辦法,用通知 step 1:在進入視圖的時候添加監視:(viewDidLoad什麼的) step 2:在鍵盤動作的時候移動視圖: step 3:在退出視圖的時候註銷通知viewDidUnload: step 4:dealloc: 這些代碼是摘自apple sample code Keyboa ...
  • if (indexPath.row % 2 == 0) { cell.backgroundColor = [UIColor magentaColor]; }else{ cell.backgroundColor = [UIColor whiteColor]; } ...
  • 移動端身份證識別SDK的研發背景: 隨著智能終端以及移動通信(4G)的迅速發展,原來運行在PC機上的信息系統逐漸轉移到智能終端上來,2016年是人工智慧元年,也是移動互聯網下半場的開始,各種APP如雨後春筍般出現在人們的視野中,電信實名制、互聯網APP實名制、徵信系統實名制相繼推出,無論從政策上還是 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...