Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

touchesBegan is called in iOS 12 but is not called in iOS 13

I have a touchesBegan method in my AppDelegate. I use it to detect taps in the status bar. I've had it there for a long time and it's worked great. Until the iOS 13 betas came out...

Ever since using iOS 13 touchesBegan has stopped being called. Nothing else related to gestures has changed in my app, nothing in my AppDelegate has changed. I don't really have much to go on other than touchesBegan is called in iOS 12 and not in iOS 13.

No luck so far though so I'm sharing this here in case someone else has had the same or a similar issue.


Update: 1 I have found the following issues which are semi related and have lead me to Apple's new UISceneDelegate in iOS 13. None of these issues explain why touchesBegan isn't being called. And as I understand the UISceneDelegate so far, I haven't yet found why touchesBegan isn't being called.

View controller responds to app delegate notifications in iOS 12 but not in iOS 13
How to detect touches in status bar
iOS13: how to detect a status bar click event?

like image 714
Xeaza Avatar asked Sep 05 '19 13:09

Xeaza


1 Answers

This is what I am doing, may not be great but only working solution so far. Happy to take improvements.

  • Create TableViewController with contents larger than it's frame.
  • On view will appear, Scroll to the end of table view.
  • Set TableViewController's frame same as StatusBarFrame and add it to Window's root viewcontroller
  • Inside scrollViewShouldScrollToTop handle ScrollToTop event and scroll to the end to get next events.
  • On StatusBar frame change, Update TableViewController's frame.

This works works with SceneDelegate as well.

ScrollToTopViewController.swift

class ScrollToTopViewController: UITableViewController {

    private let numberOfRow = 2
    private let cellIdentifier = "empty"

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.allowsSelection = false
        tableView.separatorColor = .clear
        tableView.backgroundColor = .clear
        tableView.showsVerticalScrollIndicator = false
        tableView.showsHorizontalScrollIndicator = false
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier)
        view.autoresizingMask = []
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        scrollToBottom()
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return view.frame.size.height
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfRow
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier) ?? UITableViewCell()
        cell.backgroundColor = .clear
        return cell
    }

    override func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.scrollToBottom()
        }
        print("HANDLE SCROLL TO TOP")
        return true
    }

    private func scrollToBottom() {
        tableView.scrollToRow(at: IndexPath(row: numberOfRow - 1, section: 0), at: .bottom, animated: false)
    }
}

AppDelegate.swift or equivalent SceneDelegate functions.

private let scrollToTopVC = ScrollToTopViewController()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    NotificationCenter.default.addObserver(self,
                                           selector: #selector(updateScrollToTopVC),
                                           name: UIApplication.didChangeStatusBarFrameNotification,
                                           object: nil)
    return true
}

func applicationDidBecomeActive(_ application: UIApplication) {
    updateScrollToTopVC()
}

@objc
private func updateScrollToTopVC() {
    guard let viewController = window?.rootViewController else {
        return
    }
    let statusBarFrame: CGRect

    if #available(iOS 13.0, *) {
        statusBarFrame = UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
    } else {
        statusBarFrame = UIApplication.shared.statusBarFrame
    }
    scrollToTopVC.view.frame = statusBarFrame
    viewController.addChild(scrollToTopVC)
    viewController.view.addSubview(scrollToTopVC.view)
    scrollToTopVC.didMove(toParent: viewController)
}
like image 105
k-thorat Avatar answered Oct 05 '22 07:10

k-thorat