iOS11.0でUINavigationControllerのTitleViewのタッチイベントが呼ばれない現象について


はじめに

こんにちは
UINavigationControllerにはTitleViewというプロパティがあります。
私はNavigationBarの中央に来るようTitleViewUIButtonを含む独自のカスタムViewをxibで作成して以下のように利用していました。

iOS11.0以前ではこのボタンは押すことができ、問題なく動作するのですが、
以降ではTouchEventがどうやら反応しないようです。

※ コードでTitleViewを作成している場合、TitleViewの大きさを十分に取っていればiOS11.0でも以前と変わらずTouchEventは呼ばれます

MainViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    let button = UIButton()
    button.setTitle("Button", for: .normal)
    button.frame.size = CGSize(width: 60, height: 30)
    button.addTarget(self, action: #selector(MainViewController.buttonAction), for: .touchUpInside)
    let titleView = UIView()
    titleView.backgroundColor = UIColor.cyan
    //十分な大きさを確保
    titleView.frame.size = CGSize(width: 120, height: 44)
    titleView.addSubview(button)
    button.frame.origin = CGPoint(x: titleView.frame.size.width * 0.5 - button.frame.size.width * 0.5,
                                  y: titleView.frame.size.height * 0.5 - button.frame.size.height * 0.5)
    self.navigationItem.titleView = titleView
}

解決方法

TitleViewにあてるカスタムViewのintrinsicContentSizeを設定すると
iOS11.0以前と同じくTouchEventが呼ばれるようです。

TopBarView.swift
override var intrinsicContentSize: CGSize {
    return CGSize(width: 134, height: 33)
}

試してみたこと

  • iOS11.0でisUserInteractionEnabledのデフォルト値が変わったのかと考え、 UINavigationBar等をtrueにしてみる
//デフォルトでtrueなので結果は ×
navigationItem.titleView?.isUserInteractionEnabled = true
//デフォルトでtrueなので結果は ×
navigationController?.navigationBar.isUserInteractionEnabled = true
  • UITapGestureRecognizerを設定してみる
//結果は ×
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(MainViewController.topBarTap))
self.navigationItem.titleView?.addGestureRecognizer(tapGesture)

サンプルコード

一応サンプルのコードを書いておきます。
独自に作成したView(TopBarView)は別途xibファイルでも作成しています。

MainViewController.swift
import UIKit

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.titleView = TopBarView.instantiate()
    }
}
TopBarView.swift
import UIKit

class TopBarView: UIView {

    @IBOutlet weak var button: UIButton!

    override func awakeFromNib() {
        button.setTitle("Button", for: .normal)
    }

    static func instantiate(withOwner ownerOrNil: Any? = nil) -> TopBarView {
        let nib = UINib(nibName: "TopBarView", bundle: nil)
        return nib.instantiate(withOwner: ownerOrNil, options: nil)[0] as! TopBarView
    }

    private override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override var intrinsicContentSize: CGSize {
        return CGSize(width: 134, height: 33)
    }

    @IBAction func buttonAction(_ sender: Any) {
        print("ボタンが押されました")
    }
}

さいごに

iOS11.0になりUINavigationControllerにLargeTitleが追加されたり、NavigationBarの高さ分がUIScrollViewなどで自動計算されたりと混乱してしまいますが、少しずつ慣れていけたらと思います。

参考にさせていただいた記事

見て頂いてありがとうございます。