たとえばUITableViewControllerでユーザーリストを表示している。UITableViewCell上のフォローボタンをタップしたらpopoverを表示させたい。
ポップオーバーを表示させる基準となる sourceView
とsourceRect
は下記のようなコードを書いていた。
vc.popoverPresentationController?.sourceView = cell vc.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint.zero, size: sender.bounds.size)
ポップオーバーの矢印が適切な場所を指さずに、セルの上についたり、セルの下についたり、していたので、フォローボタンの位置を適切に渡せていないのが原因ではないかと寝ながら考えた。検証してみた。
UITableViewControllerにおける「UITableViewCell上に配置したボタンの座標」を取得する方法を調べた。
UITableViewCellが表示されている座標を取得する
func followButtonAction(_ sender: UITableViewCell) { let rectInSubview = tableView.convert(cell.frame, to: self.view) print("cell#bounds \(cell.bounds)") print("cell#frame \(cell.frame)") print("rect in subview \(rectInSubview)") }
実行します。
cell#bounds (0.0, 0.0, 375.0, 294.5) cell#frame (0.0, 142.0, 375.0, 294.5) rect in subview (0.0, 142.0, 375.0, 294.5) // UITableViewを上方向にスクロールしたあと cell#bounds (0.0, 0.0, 375.0, 294.5) cell#frame (0.0, 142.0, 375.0, 294.5) rect in subview (0.0, 24.0, 375.0, 294.5)
UITableViewControllerにおけるUITableViewCellの座標が取得できていることが確認できる。
UITableViewCell上のボタンが表示されている座標を取得する
次に本命のUITableViewCell上に配置したボタンの座標を取得する。
func followButtonAction(_ sender: UITableViewCell) { let rectInCell = cell.convert(cell.followButton.frame, to: tableView) let rectInSubview = tableView.convert(rectInCell, to: self.view) print("cell#bounds \(cell.bounds)") print("cell#frame \(cell.frame)") print("rect in cell \(rectInCell)") print("rect in subview \(rectInSubview)") }
実行します。
cell#bounds (0.0, 0.0, 375.0, 294.5) cell#frame (0.0, 142.0, 375.0, 294.5) rect in cell (12.0, 196.0, 40.0, 21.0) rect in subview (12.0, 196.0, 40.0, 21.0) // UITableViewを上方向にスクロールしたあと cell#bounds (0.0, 0.0, 375.0, 294.5) cell#frame (0.0, 142.0, 375.0, 294.5) rect in cell (12.0, 196.0, 40.0, 21.0) rect in subview (12.0, 51.0, 40.0, 21.0)
UITableViewControllerにおけるUITableViewCell上に配置したフォローボタンの座標を取得することができました。
やりたかったこと
実際にはUITableViewControllerにおける座標を求める必要はありませんでした。基準となるsourceView(ここではUITableViewCell)と、フキダシの基準となるsourceRectにボタンの座標を指定すればよかった。
vc.popoverPresentationController?.sourceView = cell vc.popoverPresentationController?.sourceRect = cell.followButton.frame
ボタンの座標とは、sourceView(ここではUITableViewCell)からみた座標……つまりフォローボタンの座標(frame)を渡せばよかった。
なので下記のコードでも、前述のコードと同じ挙動となる。
vc.popoverPresentationController?.sourceView = cell.followButton vc.popoverPresentationController?.sourceRect = cell.followButton.bounds