最近工作上碰到Google Map,並用到GMUClusterManager
,它的作用簡單來說,就是會自動聚合地圖上的Marker,當User把地圖縮小時,會自動把距離接近的Marker縮成一個點,假設是把五個各為1的Marker聚合,就會縮成一個顯示為5的Marker。
詳情可以看 法蘭克的iOS世界 的這篇貼文,有完整的說明跟gif,介紹得非常詳盡。
後來設計大大給了一個有點困難的需求,就是當User把圖持續縮小時,希望到了一個臨界點之後,就不要再進行聚合,停留在原本臨界點中聚合的狀態。
舉例來說,假設User進入地圖時,MapView的Camera的Zoom設為15,大約是「左下角:大安森林公園,右上角:南京復興站」的大小,此時地圖上有12個各為「1」的Marker;當User把地圖縮小,Zoom到12時大約是「上方:北投,下方:碧潭」的範圍,這時候地圖上有5個各為「50」的Marker,就是GMUClusterManager
的神奇效果;
然後我們希望將12的這個Zoom設為臨界點,接下來User往下繼續縮小,縮到11、10、9……的時候,台北市都一樣停留在5個「50」的Marker,而不是將整個北部地區都群聚成1個「250」的Marker,這個需求該如何達成呢?
Google Map官方的文件中,有一篇關於Marker Clustering的文章,不過沒有特別提到任何上限、下限、最大、最小的觀念,除了「For best performance, the recommended maximum number of markers is 10,000」這句沒什麼用的描述。
而GMUClusterManager
中會用到的GMUDefaultClusterRenderer
,有一個參數叫maximumClusterZoom,但如同它註解中寫的,”Sets the maximium zoom level of the map on which the clustering should be applied. At zooms above this level, clusters will be expanded.”,實際上的作用是讓任何大於它的Zoom,都不要再做任何群聚,例如設為15時,那放大到超過15後,就全部散開成一堆「1」的Marker,因此完全不是我們要的效果。
後來我再仔細看了一下官方文件,發現文件最後有提到一段Customize marker clustering:
You can provide a custom implementation for the
GMUClusterRenderer
,GMUClusterIconGenerator
, orGMUClusterAlgorithm
. You can base your custom implementation on the sample implementation of these protocols included in the utility library, or you can code a fully custom implementation by fulfilling the protocols.
所以照著這個想法,我跑去翻了一下我們選用的GMUNonHierarchicalDistanceBasedAlgorithm
的Code,發現.m檔中有一段- (NSArray<id<GMUCluster>> *)clustersAtZoom:(float)zoom
的function,雖然Objective C要看懂真的有點難…不過大概猜一下,這段有輸入型別為float
的zoom
,輸出的則是GMUCluster
,那應該就是這段在處理Zoom跟群聚的邏輯。
因此,照著文件試試看,我設了一個自訂的class,繼承GMUNonHierarchicalDistanceBasedAlgorithm
,並override上述的function,用super
去輸出它原本的邏輯,但加入zoom
的判斷條件,結果如下:
然後在放入地圖的View Controller裡宣告GMUClusterManager
的時候,用這個我自己客制的Algorithm 的 class:
結果就成功了!當user把地圖縮小到小於12時,地圖上群聚的UI真的就停留在12的階段,不會再進一步群聚!
希望這篇文可以幫助到有需要的人 :)