LoginSignup
35
22

More than 3 years have passed since last update.

コピペで使えるPopover(swift5.0)大全

Last updated at Posted at 2019-09-11

はじめに

iOSのPopoverについて調べたまとめです。(swift5.0)

iPhoneで表示

iPhoneでのPopover表示です。なんとなくセルタップ時にセルからPopoverを表示してみました。

ViewController.swift
extension ViewController: UITableViewDelegate {
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let cell = tableView.cellForRow(at: indexPath) else {
            return
        }
        let viewController = PopoverViewController() //popoverで表示するViewController
        viewController.modalPresentationStyle = .popover
        viewController.preferredContentSize = viewController.view.frame.size

        let presentationController = viewController.popoverPresentationController
        presentationController?.delegate = self
        presentationController?.permittedArrowDirections = .up
        presentationController?.sourceView = cell
        presentationController?.sourceRect = cell.bounds

        present(viewController, animated: true, completion: nil)
    }
}

extension ViewController: UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyle(for controller: UIPresentationController,
                                   traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        return .none
    }
}

デリゲートの実装は注意しましょう!!(iPhone 横向きでポップオーバー表示するとこわれた\(^o^)/)

ナビゲーションのbarButtonItemから表示

navigationItembarButtonItemからのPopover表示です。

ViewController.swift
@objc func showPopover(_ sender: UIBarButtonItem) {
        let viewController = PopoverViewController() //popoverで表示するViewController
        viewController.modalPresentationStyle = .popover
        viewController.preferredContentSize = viewController.view.frame.size

        let presentationController = viewController.popoverPresentationController
        presentationController?.delegate = self
        presentationController?.permittedArrowDirections = .up
        presentationController?.barButtonItem = sender

        present(viewController, animated: true, completion: nil)
}

Popoverを閉じないようにする

Popoverは通常枠外をタップすると閉じますが、枠外をタップしても閉じないようにします。

ViewController.swift
extension ViewController: UIPopoverPresentationControllerDelegate {
    func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
        return false
    }
}

Popoverの吹き出しの色設定

popoverの吹き出しに色を設定します。

ViewController.swift
extension ViewController: UITableViewDelegate {
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let cell = tableView.cellForRow(at: indexPath) else {
            return
        }
        let viewController = PopoverViewController() //popoverで表示するViewController
        viewController.modalPresentationStyle = .popover
        viewController.preferredContentSize = viewController.view.frame.size

        let presentationController = viewController.popoverPresentationController
        presentationController?.delegate = self
        presentationController?.permittedArrowDirections = .up
        presentationController?.sourceView = cell
        presentationController?.sourceRect = cell.bounds
        presentationController?.backgroundColor = .red

        present(viewController, animated: true, completion: nil)
    }
}

Popoverの背面のViewのジェスチャの有効化

Popoverの背面のViewのジェスチャを有効化します。背面のtableViewのジェスチャを有効化しました。passthroughViewsにtableViewを指定しているのでtableViewをスクロールやタップしてもPopoverは閉じません。navigationBarをタップするとPopoverは閉じます(tableViewの範囲外)。

ViewController.swift
extension ViewController: UITableViewDelegate {
   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let cell = tableView.cellForRow(at: indexPath) else {
            return
        }
        let viewController = PopoverViewController() //popoverで表示するViewController
        viewController.modalPresentationStyle = .popover
        viewController.preferredContentSize = viewController.view.frame.size

        let presentationController = viewController.popoverPresentationController
        presentationController?.delegate = self
        presentationController?.permittedArrowDirections = .up
        presentationController?.sourceView = cell
        presentationController?.sourceRect = cell.bounds
        presentationController?.passthroughViews = [tableView]

        present(viewController, animated: true, completion: nil)
    }
}

おまけ無限Popover

PopoverからPopoverを表示する

表示したPopoverからさらにPopoverを表示します。単純にPopoverのViewControllerのボタン押下時にPopoverを表示しているだけです。

PopoverViewController.swift
@IBAction func showPopover(_ sender: UIButton) {
        let viewController = PopoverViewController()
        viewController.modalPresentationStyle = .popover
        viewController.preferredContentSize = viewController.view.frame.size

        let presentationController = viewController.popoverPresentationController
        presentationController?.delegate = self
        presentationController?.permittedArrowDirections = .up
        presentationController?.sourceView = sender
        presentationController?.sourceRect = sender.bounds

        present(viewController, animated: true, completion: nil)
    }

Popoverの背面のViewからPopoverを表示する

Popoverの背面のViewのジェスチャの有効化で背面のtableViewのジェスチャを有効化しましたがPopover表示中にセルをタップしても下記のようなエラーが出てPopoverが表示されません。

Warning: Attempt to present <PopoverTest.PopoverViewController: 0x7fb4ff613e90>  on <PopoverTest.ViewController: 0x7fb4ff507d10> which is already presenting (null)

ちょっといじってPopoverの上にPopoverを表示するようにします。

ViewController.swift
extension ViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let cell = tableView.cellForRow(at: indexPath) else {
            return
        }
        let viewController = PopoverViewController() //popoverで表示するViewController
        viewController.modalPresentationStyle = .popover
        viewController.preferredContentSize = viewController.view.frame.size

        let presentationController = viewController.popoverPresentationController
        presentationController?.delegate = self
        presentationController?.permittedArrowDirections = .up
        presentationController?.sourceView = cell
        presentationController?.sourceRect = cell.bounds
        presentationController?.passthroughViews = [tableView]

        topViewController.present(viewController, animated: true, completion: nil)
    }

    var topViewController: UIViewController {
        var target: UIViewController = self
        while let presentedViewController = target.presentedViewController {
            target = presentedViewController
        }
        return target
    }
}

さいごに

passthroughViewsなんかあったんだ!!という驚きからこの記事を書いてみました。意外と古くiOS8.0からあったみたいですね。(公式ドキュメント

色々書きましたが1個目2個目以外はあまり使う機会がないと思います:neutral_face:

35
22
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
22