酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

UITableViewControllerにおける「UITableViewCell上に配置したボタンの座標」を取得する

たとえばUITableViewControllerでユーザーリストを表示している。UITableViewCell上のフォローボタンをタップしたらpopoverを表示させたい。

f:id:ch3cooh393:20200108223546p:plain

ポップオーバーを表示させる基準となる sourceViewsourceRect は下記のようなコードを書いていた。

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