Chapters

Hide chapters

Catalyst by Tutorials

First Edition · iOS 13 · Swift 5.1 · Xcode 11

Before You Begin

Section 0: 3 chapters
Show chapters Hide chapters

9. The Mouse
Written by Andy Pereira

Just like a keyboard, the mouse is a toolset you may not have encountered if you’ve focused solely on iOS development so far. Catalyst makes working with the mouse easy, since it provides a familiar pattern, and it gives you a great amount of control in the process.

In this chapter, you’ll learn how to implement UIHoverGestureRecognizer and you’ll take a look at the differences between iOS/iPadOS and touch targets in macOS.

Getting started

Open the starter project for this chapter. Build and run for macOS and you’ll see that you’re starting off with a complete UI. Add a few entries and then move your mouse around the app. Not much actually happens, aside from seeing the curor change from an arrow to an iBeam if you hover over the top of the text view.

On macOS, you can give your users more feedback when the cursor moves over items. You’re going to add two gestures to make the app feel more responsive.

The hover gesture recognizer

New to iOS 13 is UIHoverGestureRecognizer, a gesture recognizer that responds to mouse movements within your view. As with other gesture recognizers, it requires a target and action.

To start, open EntryTableViewCell.swift. Add the following to the end of awakeFromNib().

addHoverGesture()

Then add the following method to the class:

private func addHoverGesture() {
  let hoverGesture
    = UIHoverGestureRecognizer(target: self,
                               action: #selector(hovering(_:)))
  contentView.addGestureRecognizer(hoverGesture)
}

This method does the following:

  • It creates a hover gesture recognizer, setting self as the target, and an action that you’ll set up in the next step.
  • It adds the hover gesture to the content view of the cell.

Next, add the following to the same class:

@objc private func hovering(_ recognizer: UIHoverGestureRecognizer) {
  // 1
  guard !isSelected else { return }
  // 2 
  switch recognizer.state {
  // 3
  case .began, .changed: 
    backgroundColor = .systemGray
  // 4
  case .ended:
    backgroundColor = nil
  default:
    break
  }
}

Here, you can see how you respond to the hover events:

  1. This ensures that nothing happens if you’ve already selected the cell.
  2. The gesture recognizer passes itself as a parameter to this method. You check the state of the gesture recognizer.
  3. If the hover is starting (i.e., .began) or moving around (i.e., .changed), you change the background color of the cell.
  4. Once the mouse is no longer hovering over the view (i.e., .ended), you remove the color you set.

Build and run the app then add a few entries and hover your mouse over the Table view. You should now see that all the cells, except for the cell you selected, change background color while the mouse is over it. Once the mouse leaves the view, it changes back to having no background color.

There’s one more place where you can add a hover gesture to give your app more finesse.

Open EntryTableViewController.swift and add the following to supplementaryDataSource(), just before it returns reusableView:

let hoverGesture 
  = UIHoverGestureRecognizer(target: self,
      action: #selector(self.hovering(_:)))
reusableView.addGestureRecognizer(hoverGesture)

Once again, this code creates a hover gesture and adds it to the reusable view that the collection view’s header returns.

Next, add the following method to the class:

@objc private func hovering(_ recognizer: UIHoverGestureRecognizer) {
  guard let view = recognizer.view else { return }
  switch recognizer.state {
  case .began, .changed:
    view.backgroundColor = UIColor(named: "PrimaryTint")
    view.tintColor = .white
  case .ended:
    view.backgroundColor = nil
    view.tintColor = UIColor(named: "PrimaryTint")
  default:
    break
  }
}

Here, you respond to the event over the Reusable view and change the color of the Header view to reflect the mouse hover.

Build and run, then hover over the camera button in the entry view. It should now change colors as you mouse over it.

A few notes

Keep in mind that the interface guidelines for iOS state that you should keep touch targets for interactive elements to a minimum of 44pt × 44pt. The cursor gives you a lot more flexibility when your app is running on macOS. If you’re creating macOS-specific UI elements, you can use smaller elements if it makes sense for your app.

If you’ve worked with macOS in the past, you may have used NSCursor to change the cursor’s type. This isn’t available in Mac Catalyst without quite a bit of extra work. Luckily, UI elements found in UIKit support changing their cursor type out of the box. You can already see that the resize arrow cursor appears when you hover over the line between the Table view and the Entry view, indicating you can resize it.

You also have access to haptic feedback on both platforms. You could easily setup haptic feedback when mousing over an area, if your app requires it. Keep Apple’s guidelines in mind, and remember not to overstimulate your users.

Bridging the gap

At the time of this writing, some frameworks or tools that are available in macOS are not available in Mac Catalyst, like NSCursor. If you find yourself needing to utilize some of these components, you can create an AppKit bundle. Creating a bundle and accessing its contents is out of the scope of this book, but here are some pointers:

  • Only embed the bundle in macOS.
  • You need to create a class in the bundle, and make it the Principal Class. This is done inside the Info.plist of the bundle.
  • While possible in Swift, you may find that Objective-C is a bit easier for loading classes, and calling code dynamically.

Working with bundles in this manner can be challenging, especially if you are unfamiliar with it. You may find it is worth going down this path if you really need access to something, or you may be content waiting for Apple to provide the missing piece later down the road.

You can read more about bundles from Apple’s bundle programming guide here: https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/Introduction/Introduction.html

Key points

  • Add hovering to views by adding a hover gesture recognizer to give your user more visual feedback.
  • Hover gesture recognizers work similarly to other gesture recognizers.
  • You are still somewhat limited on working with the mouse when building an iPad app on the Mac.
  • Bundles may provide a solution to missing functionality

Where to go from here?

In this chapter, you learned how easy it is to get started responding to mouse hover events and the differences between iOS touch targets vs. macOS.

You can find Apple’s Human Interface Guidelines for the mouse and trackpad here: https://developer.apple.com/design/human-interface-guidelines/macos/user-interaction/mouse-and-trackpad/.

You can read more about UIHoverGestureRecognizer from Apple’s website: https://developer.apple.com/documentation/uikit/uihovergesturerecognizer.

To learn more about the possible states for a gesture recognizer, refer to the following Apple documentation: https://developer.apple.com/documentation/uikit/uigesturerecognizer/state.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2026 Kodeco Inc.