不少應用的都會使用到地圖控件,咱們目前使用到地圖的場景是規劃無人機的飛行路線。最多見的是規劃一塊要飛行的區域,而後生成巡航的路線,最後用拍到的照片進行建模。有了模型後就能夠得到場地的一些數字化信息。 post
咱們有些客戶要建模的區域在郊區,所以地圖的信息準確對於咱們規劃飛行區域的幫助很大。咱們調研後發現高德和百度的圖源質量各有長短,所以咱們決定同時接入多個地圖源。客戶能夠根據現場的具體狀況選擇地圖源。咱們的地圖控件在規劃路線時有不少的自定義 UI 須要展現,下面是咱們的規劃正射飛行的一張設計圖:性能
若是咱們使用地圖 SDK 提供的繪製方法,一樣的自定義 UI 在不一樣的地圖源上就要重複的實現一遍。若是咱們支持三個地圖源,那麼就要針對三個地圖源提供的方法實現三套 UI。這顯然不是一個能夠接受的方案。所以咱們決定將自定義 UI 繪製抽離出來,這樣最複雜的自定義 UI 繪製只要維護一份代碼,地圖源當作組件能夠替換。 最後在手機上看起來就像下圖這樣,地圖源在最底層,自定義 UI 在地圖上層。這樣更換地圖源只是最底層的視圖發生了變化:下面展現自定義 UI 和地圖源映射的過程:測試
若是要添加一個新元素,那麼調用地圖的接口獲取這個標註的地理座標在地圖上的視圖座標,接着在自定義視圖上添加標註。顯然若是地圖的展現區域變了,標註的座標也須要一塊兒改變。所以須要監聽地圖的區域變更事件,一旦改變,須要從新計算標註的平面座標,更新標註位置。 換成僞代碼是這樣的: 除了自定義的 UI 的展現外,有時自定義的 UI 還要支持交互。在我眼前的業務場景裏,須要交互的元素交互時都是處在視圖的最頂層。若是可交互元素和展現元素放在一個視圖裏,就須要有狀態區分哪些元素會響應交互事件。由於最底層的地圖也要接收交互事件(用戶可能會調整地圖)。所以視圖的 hittest 處理起來就會有些雜亂,所以我將可交互的元素都統一放在一個圖層裏。這個圖層裏全部的元素都響應用戶交互事件。其餘的交互事件最後都會傳給底部的地圖。總體的視圖結構大概就是這樣:設計
這個方案的優點是將自定義 UI 的實現與具體的地圖 SDK 隔離,當地圖源切換時,自定義 UI 能夠直接複用。可是這個方案也有一個固有缺陷:當地圖持續響應用戶交互,自定義的 UI 繪製會略有卡頓。3d
若是將 UI 經過地圖 SDK 添加到地圖上,自定義 UI 的繪製與地圖的渲染髮生在同一幀裏。所以任意一幀裏,自定義 UI 和地圖的位置老是對應的,從用戶的角度看就是圖形的變換很順滑。可是咱們的選擇的方案,自定義的 UI 變換前有兩個步驟:收到地圖區域變化通知,從新計算圖形在地圖上的平面座標。假設手機沒有性能問題,那麼地圖原生圖層的繪製頻率是 60Hz。當用戶進行連續縮放時,地圖的圖層每秒繪製 60 次。用戶感受很順滑。地圖區域變化的外界通知的頻率因爲性能考慮會低於 60Hz,所以即使從新計算圖形座標、繪製能夠在 1/60 秒完成,自定義 UI 的渲染頻率仍是會低於 60Hz。給用戶的體驗就是連續移動時,自定義 UI 沒有那麼跟手。cdn
至於自定義 UI 的繪製延遲是否能夠接受這就看各自的場景了。可是從個人測試結果看,雖然性能會差一些,可是大部分場景不會影響到用戶的使用。blog