iPad iOSアプリケーション向けのトラックパッドサポート (UIPointerInteraction) を追加

ユーザーはiPadにトラックパッドを接続して、iPadでマウスを使用できます。さらに、トラックパッドとともにAppleのキーボードフォリオを使うことができます。ユーザーがマウスのカーソルを動かすと、さまざまなエレメントが強調表示されます。

<img width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/849a3ae8-cc9f-d52a-4ec0-cf61d48737e4.gif">

この記事では、`SwiftUI` アプリケーションや `UIKit + UIStoryboard` アプリケーションにトラックパッドのポインターの相互作用 (`Pointer Interaction`) を追加する方法について説明します。

## SwiftUI 用

`.hoverEffect()` 修飾子をビュー要素に追加すると、トラックパッドの相互作用を有効にできます。​たとえば、

```swift
struct ContentView: View {
    var body: some View {
        Button(action: {}, label: {
            Image(systemName: "square.and.arrow.up")
        })
            .font(.system(size: 50))
            .foregroundColor(.blue)
            .hoverEffect(.highlight)
    }
}
```

`.hoverEffect(.highlight)` は次のように見えます

<img width="200" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/f8f1e0ef-9c10-4dfc-b8b1-6ee87538a4d2.gif">

`.hoverEffect(.lift)` は次のように見えます

<img width="200" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/e21ff018-64d7-b1f7-8c1f-263af5633c38.gif">

## UIStoryboard のボタンの場合

ストーリーボードの `UIButton` ボタンにポインタのインターアクションをすばやく追加できます。`Pointer` セクションの `Interaction enabled` というチェックボックスをクリックするだけです。

<img width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/b1c1a330-430a-99b4-83ee-5676828c5f71.png">

外観はこのようになります：

<img width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/7443cd81-5e07-c21b-dd1a-e1d3ca40d9c5.gif">

## UIKitを使った他のビューには

`UIStoryboard` をご使用で、他のビューエレメントにポインターインタラクションを追加したい場合、 `UIPointerInteraction` をご活用いただけます。

最初にビューエレメントをバリアブルとしてコードに加えてください：

```swift
@IBOutlet weak var button: UIView!
```

このボタンはお使いの `UIStoryboard` のビューエレメントにリンクしますのでご注意ください。

また、`UIPointerInteraction` 変数をプログラムクラスに追加してこれを初期化します。

```swift
var interaction: UIPointerInteraction!

override func viewDidLoad() {
    super.viewDidLoad()
    interaction = UIPointerInteraction(delegate: self)
}
```

現在、呼び出しによりポインターインタラクションをビューエレメント (`button`) に追加できるようになっています。

```swift
button.addInteraction(self.interaction)
```

また、`UIPointerInteractionDelegate` というデリゲートの追加も必要です。

```swift
extension ViewController: UIPointerInteractionDelegate {
    
    func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle? {
        if let view = interaction.view {
            let preview = UITargetedPreview(view: view)
            return UIPointerStyle(effect: UIPointerEffect.lift(preview))
        }
        return nil
    }
    
}
```

こちらのようになります：

<img width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/849a3ae8-cc9f-d52a-4ec0-cf61d48737e4.gif">

### ポインターのスタイル

```swift
func pointerInteraction(_ interaction: UIPointerInteraction, styleFor region: UIPointerRegion) -> UIPointerStyle?
```

この最初の関数では、ポインターのインタラクションのスタイルを指定します。例えば、`UIPointerEffect.highlight(preview)` 、`UIPointerEffect.lift(preview)` 、または `UIPointerEffect.hover(preview, preferredTintMode: .overlay, prefersShadow: true, prefersScaledContent: true)` が利用できます。

### トラックパッドのポインターが指定範囲に入った時または指定範囲から出た時に実行するアクション

ユーザーのトラックパッドのポインターが特定の範囲に入った時または特定の範囲から出た時にアクションを実行することができます。

```swift
func pointerInteraction(_ interaction: UIPointerInteraction, willEnter region: UIPointerRegion, animator: UIPointerInteractionAnimating) {
    if let view = interaction.view {
        // TODO
    }
}

func pointerInteraction(_ interaction: UIPointerInteraction, willExit region: UIPointerRegion, animator: UIPointerInteractionAnimating) {
    if let view = interaction.view {
        // TODO
    }
}
```

### ビュー要素の範囲を手動で定義

ビュー要素の範囲を手動で定義したい場合には、この関数を拡張に追加できます。

```swift
func pointerInteraction(_ interaction: UIPointerInteraction, regionFor request: UIPointerRegionRequest, defaultRegion: UIPointerRegion) -> UIPointerRegion? {
    if let view = interaction.view {
        // TODO
    }
}
```

___

ポインターインタラクションを実装すると、トラックパッドでiPadを使用しているユーザーにより良いエクスペリエンスを提供することができます。これらのインタラクションにより、ユーザーはアプリケーションでクリックすべき場所をさらによく把握することができるようになります。

---

:relaxed: [Twitter @MszPro](https://twitter.com/MszPro)

:sunny: [私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。](http://mszpro.com/ioskiji/)
<img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">