Pointer Interaction Tutorial for iOS: Supporting the Mouse and Trackpad

This tutorial will show you how to use the iOS pointer API for simple cases, and some more complex situations, with both UIKit and SwiftUI. By Warren Burton.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

Adding a Simple Hover Effect

In this section you’ll add a lift effect to the Play/Reset button.

Go to the Project navigator. Open the SwiftUI Views folder, and then open GameView.swift. This is the game interface. This interface is very similar to the UIKit version.

In the body of GameView, locate GameKeyboard(gameEngine: gameEngine). Below that, you’ll find Button.

At the end of the button description is a comment, //add button hover here. Delete the comment, and replace it with this line:

.hoverEffect(.lift)

Build and run and capture the pointer. Go to the SwiftUI section of the app. Now the Play button will react whenever the pointer enters the button.

.hoverEffect is a modifier on View. This means it’s not limited to buttons — you can use it for anything on the screen that the pointer passes over!

Adding an OnHover Handler

You can also add more complex pointer interactions to your SwiftUI. To do that, you’ll need to detect the presence of the pointer within a view. In this section, you’ll upgrade the end screen for a lost game, as you did for UIKit.

In the Project navigator, in the SwiftUI Views folder, open LoseView.swift.

First, add these properties in LoseView:

@State var isHoverInside: Bool = false

var shouldDisplayHover: Bool {
  return isHoverInside || UIDevice.current.userInterfaceIdiom == .phone
}

isHoverInside will be updated when the pointer enters the view you’re interested in. shouldDisplayHover decides if you should show the hover state or not. iPhones don’t have pointer interactions, so you will always show the effect on iPhone. Remember, you must not use pointer interactions as the only way to access functionality or information, as they are not available to all users.

Next, locate the comment //add on hover here at the bottom of ZStack. Replace it with this:

//1
.onHover { inside in
  self.isHoverInside = inside
}
//2
if shouldDisplayHover {
  HStack {
    Rectangle().foregroundColor(.clear)
    GeometryReader { _ in
      SpeechBubble(message: "It's OK.\nTap anywhere to try again")
        .offset(self.bubbleOffset)
    }
  }
}

In this block:

  1. You add an onHover event to the central VStack. You update the value of isHoverInside during the event. onHover only supplies one piece of information: It tells you whether the pointer is in or out.
  2. You use the state of isHoverInside to add SpeechBubble conditionally to the outer ZStack.

Finally, make the cat happy! Find this line in the inner VStack:

Text("\(sadCat)")

Change it to this:

Text("\(isHoverInside ? happyCat : sadCat)")

Build and run and capture the pointer. Go to the SwiftUI section of the app. When you lose, the speech bubble will appear when you place the pointer in the central area.

swift UI win state view

Note: You can use either hoverEffect or onHover, but not both, for a given View hierarchy. onHover takes precedence.

In the interest of not over-baking the cake, you’ll finish here. You’ve seen that SwiftUI allows you to interact with the pointer, but with less control than UIKit.

Where to Go From Here?

You can download the finished project using the Download Materials button at the top or bottom of this tutorial.

In this Pointer Interaction Tutorial for iOS, you learned how to:

  • Add simple automatic pointer effects.
  • Provide custom pointer effects.
  • Interact with the pointer position and animation sequence.

You’ve seen that pointer interactions can supplement the normal touch interactions in an iOS application. And you’ve learned how you can add these interactions with very little work! You’ve also seen that UIKit has a rich pointer API that SwiftUI doesn’t yet match. Hopefully, you’ll see some of these interesting interactions in future releases of SwiftUI.

For now, most people won’t be using a pointer device with their iPad. So developing complex pointer interactions might not be the best use of your time. But it is a way to add some fun and charm to the UI. Think of the cool Easter eggs you could make!

Remember to check the Human Interface Guidelines for pointer interactions.

I look forward to seeing what you do with this API in your own applications. If you have any suggestions or questions, or if you want to show off what you did to improve this project, join the discussion below.