GMSMapViewの上に自分で作ったUIViewとかを配置する方法

GMSMapViewの上には通常マーカーとかのAPIから提供されてるオブジェクトしか置けない。

しかし、マーカーのとなりに常にインフォウィンドウ的なのを表示させておきたい場合もある。マーカーにはデフォルトでインフォウィンドウがあって、タップして選択すると表示されるが、マップ中のどれか一つのマーカーのインフォウィンドウしか出ない。でも画面内にあるマーカーはどれもインフォウィンドウ開きっぱなしにしたい場合もある。

擬似的にそういう画面を作る方法があったのでメモしておく。

まず、GMSMapView中のマーカーの緯度経度を、画面上の座標に変換する必要がある。変換にはGMSMapViewのプロパティであるところの(GMSProjection *)projectionを用いる。

マーカーのクラスとかに、

CGPoint point = [self.map.projection pointForCoordinate:self.position];

などとおもむろに書き込んで座標を取得する。 しかるのちにUIViewなどの欲しい部品を設定する。

UIView *myView = [[UIView alloc]initWithFrame:CGRectMake(point.x, point.y, 100, 50)];
myView.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
UILabel *myLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 100, 50)];
myLabel.text = @"テスト";
[myView addSubview:myLabel];

これにより幅100、高さ50のインフォウィンドウもどきが設定された。

これをマップビューにaddSubviewすればインフォウィンドウもどきが表示されるはずである。 が、マップを移動したりとか拡大縮小したりするとマーカーの位置とずれる。このインフォウィンドウは画面の座標に貼り付けてあるから当然なのだが、自分の場合は何秒かに一回removeFromSuperviewして再度新しい座標を取得して配置し直すことで擬似的に表現している。あるいはマップビューが止まった時のデリゲートメソッド- mapView:idleAtCameraPosition: を使ってもまあまあ許容範囲という感じだ。

for (int i = 1; i < self.mapView.subviews.count; i++)
    {
        [self.mapView.subviews[i] removeFromSuperview];
    }

こんな感じでビューを消すと意図した通りになる気がする。int i = 0 から始めるとマップビューまで消えて面白い感じになる。