Swipe(スワイプ)とは:モバイル開発におけるスワイプ処理

著者: IT Sectr 公開日: 2026-02-27 読了時間: 8 分
Swipe(スワイプ)は、ユーザーが画面上で指を一方向(右、左、上、下)に動かす離散的なジェスチャーです。ドラッグとは異なり、スワイプは継続的な動きを追跡しません。指が最小しきい値を超えて画面から離れた後、完了したアクションとして認識されます。Nielsen Norman Group(2024)のUX調査によると、スワイプはタップに次いでモバイルアプリで2番目に頻繁なジェスチャーであり、ユーザーインタラクションの23%を占めています。

重要なポイント

  • スワイプは離散的なジェスチャー:しきい値を超えて指を離した後、完了したアクションとして認識されます。
  • iOSでは、スワイプ処理はUISwipeGestureRecognizerを使用し、方向と指の数を設定して行います。
  • Androidでは、GestureDetectorとonFling(MotionEvent)またはOnSwipeTouchListenerを使用して簡略化されたAPIを提供します。
  • スワイプのしきい値はiOSで約20px(viewConfiguration)、AndroidではVelocityTrackerで設定可能です。
  • リスト(UITableView/RecyclerView)には、手動認識ではなくUISwipeActionsConfigurationやItemTouchHelperといった組み込みメカニズムを使用します。

スワイプとは?

スワイプとは、画面上で指を素早く滑らせ、指を離して終了する動作です。スワイプは短く(要素をめくる)も長く(カーテンを開く)も可能ですが、重要な特徴は離散性です。システムはこれを連続的な座標のシーケンスではなく、単一のイベントとして認識します。

モバイルOSは、最小距離(しきい値)、最小速度(ベロシティ)、方向の3つのパラメータに基づいてスワイプを検出します。指の動きが遅い、または距離が不十分な場合、システムはそのジェスチャーをパンニングまたはタップとして解釈します。しきい値はプラットフォームによって異なります。iOSはUISwipeGestureRecognizerに固定しきい値の定数を使用し、AndroidはViewConfiguration.getScaledTouchSlop()を使用して、画面密度に応じて約8〜16dpを返します。

Android Developers Documentationによると、GestureDetectorのonFling(スワイプ)は100 px/s以上の速度、50px以上の距離で発火します。IT Sectrでは、ナビゲーション(ギャラリー、カードインターフェース、オンボーディング)にスワイプを使用しています。このジェスチャーはあらゆる年齢のユーザーにとって直感的です。

スワイプ vs パンニング:違いは何ですか?

スワイプとパンニング(pan/drag)は、どちらも画面上で指を動かすことを含みますが、異なるタイプのジェスチャーです。スワイプは離散的で「1つのアクションを実行する」ことを意味し、パンニングは継続的で「指が画面にある間はオブジェクトを移動する」ことを意味します。

パラメータ スワイプ(Swipe) パン/ドラッグ(Pan/Drag)
タイプ 離散的 継続的
イベント 単一(認識/非認識) 複数(.began → .changed → .ended)
速度 高速(素早い動き) 任意(ゆっくりした動き)
iOSの例 UISwipeGestureRecognizer UIPanGestureRecognizer
Androidの例 GestureDetector.onFling() GestureDetector.onScroll()
シナリオ メールの削除、ページをめくる マップの移動、ファイルのドラッグ
座標追跡 なし(方向のみ) あり(継続的な座標更新)

スワイプとパンニングの選択はタスクによって異なります。要素に対するアクション(削除、アーカイブ、メニューを開く)にはスワイプを使用します。直接操作(移動、拡大縮小)にはパンニングを使用します。同じ要素でジェスチャーを混在させるには、require(toFail:)またはカスタムロジックが必要です。

iOSでのスワイプ:UISwipeGestureRecognizer

UISwipeGestureRecognizerはUIGestureRecognizerのサブクラスで、4方向のいずれかでの離散的なスワイプを認識します。UIPanGestureRecognizerとは異なり、中間の.changedイベントを生成しません。認識されると、アクションは正確に1回呼び出されます。

directionプロパティ(UISwipeGestureRecognizer.Direction)は追跡する方向(.left、.right、.up、.down)を設定します。マスクを使用して方向を組み合わせることもできます(水平スワイプの場合は[.left, .right])。numberOfTouchesRequiredプロパティは指の数を指定します(デフォルトは1)。UISwipeGestureRecognizerには設定可能な距離しきい値はありません。iOSは約20pxの組み込み値を使用しており、信頼性の高い認識に十分です。

UISwipeGestureRecognizerは離散的な認識器であるため、UIPanGestureRecognizerと競合しません。ゆっくりした動きはpanを、素早い動きはswipeをトリガーします。ただし、同じビューにUITapGestureRecognizerが共存する場合、誤ったタップ認識を防ぐためにrequire(toFail:)が必要になることがあります。

Androidでのスワイプ:GestureDetector

Androidでスワイプ認識のための主要なAPIは、OnGestureListenerコールバックを持つGestureDetector、具体的にはonFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)メソッドです。GestureDetectorは指の初期位置と最終位置、軸に沿った移動速度、距離を分析し、しきい値を超えた場合にonFlingを呼び出します。

最小しきい値はViewConfigurationを介して設定可能です。VelocityTracker.getMinVelocity()(約100 px/s)およびViewConfiguration.getScaledTouchSlop()(約8〜16dp)です。カスタムのOnSwipeTouchListenerは、APIを簡素化する一般的なパターンで、開発者が手動で方向と速度を計算する必要がありません。Android Support Libraryには組み込みの「SwipeDetector」は含まれていないため、カスタムラッパーが標準的な解決策です。

リストでのスワイプには、GoogleはRecyclerViewのItemTouchHelper.SimpleCallbackを推奨しています。これにより、ジェスチャー検出、アニメーション、onSwiped()コールバックが抽象化されます。IT Sectrでは、ViewPager2やカードインターフェースにカスタムのSwipeListenerを使用しています。これにより、パフォーマンスを犠牲にすることなくスワイプ感度を制御できます。

リストでのスワイプ:SwipeActionsとItemTouchHelper

リスト(UITableView、RecyclerView)向けに、AppleとGoogleは専用のAPIを提供しています。これらは手動でUISwipeGestureRecognizerを追加する代わりに使用します。これらのAPIはアクションボタン、カスタムアニメーション、「スワイプして削除」ジェスチャーをサポートしており、モバイルアプリケーションの標準的なパターンです。

iOS(11+)では、UISwipeActionsConfigurationを使用します。tableView(_:leadingSwipeActionsConfigurationForRowAt:)メソッドはUIContextualActionの配列(タイトル、スタイル(destructive、normal)、ハンドラーを持つボタン)を返します。たとえば、「削除」は赤い背景の.destructive、「アーカイブ」はグレーの背景の.normalです。システムはボタンの表示をアニメーション化し、タップ後にcompletionブロックを呼び出します。

Androidでは、ItemTouchHelper.SimpleCallbackをItemTouchHelper.attachToRecyclerView()を介してRecyclerViewにアタッチします。パラメータには方向フラグ(start、end、up、down)とonSwiped(viewHolder、direction)コールバックが含まれます。onSwiped内では、アニメーション付きでアイテムを削除するためにadapter.notifyItemRemoved(position)が呼び出されます。ItemTouchHelperは、ジェスチャー、スクロールとの競合、スワイプが完了しなかった場合のアイテムの復帰を自動的に処理します。Google I/O 2024によると、リストにスワイプアクションがあるAndroidアプリの70%でItemTouchHelperが使用されています。

SwiftとKotlinのコード例

例1:iOSでの左スワイプ(Swift)

ビューにUISwipeGestureRecognizerを追加して、前の画面に戻ります。コードは.left方向での最小限の認識器設定を示しています。

swift
import UIKit

class CardViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let swipeLeft = UISwipeGestureRecognizer(
            target: self,
            action: #selector(handleSwipeLeft(_:))
        )
        swipeLeft.direction = .left
        swipeLeft.numberOfTouchesRequired = 1
        view.addGestureRecognizer(swipeLeft)
    }

    @objc private func handleSwipeLeft(_: UISwipeGestureRecognizer) {
        guard let nav = navigationController else { return }
        if nav.viewControllers.count > 1 {
            nav.popViewController(animated: true)
        } else {
            nav.dismiss(animated: true)
        }
    }
}

認識器はコントローラーのルートビューにアタッチされます。navigationController.viewControllers.countのチェックにより、スタックに前の画面がある場合にのみpopが実行されることを保証します。モーダルコントローラーの場合はdismissが使用されます。このコードは状態チェックを必要としません。UISwipeGestureRecognizerは離散的であり、認識に成功した場合にのみアクションを呼び出します。

例2:Androidでのスワイプ(Kotlin)カスタムOnSwipeTouchListener

スワイプの方向を判定し、onSwipeLeft/Rightコールバックを呼び出すシンプルなGestureDetectorラッパーを実装します。

kotlin
import android.content.Context
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View

open class OnSwipeTouchListener(context: Context) : View.OnTouchListener {

    private val gestureDetector = GestureDetector(context, GestureListener())

    override fun onTouch(v: View, event: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(event)
    }

    private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {

        companion object {
            private const val SWIPE_THRESHOLD = 100
            private const val SWIPE_VELOCITY_THRESHOLD = 100
        }

        override fun onFling(
            e1: MotionEvent?,
            e2: MotionEvent,
            velocityX: Float,
            velocityY: Float
        ): Boolean {
            val diffX = e2.x - e1!!.x
            val diffY = e2.y - e1.y

            if (Math.abs(diffX) > Math.abs(diffY)) {
                if (Math.abs(diffX) > SWIPE_THRESHOLD
                    && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD
                ) {
                    if (diffX > 0) onSwipeRight()
                    else onSwipeLeft()
                    return true
                }
            } else {
                if (Math.abs(diffY) > SWIPE_THRESHOLD
                    && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD
                ) {
                    if (diffY > 0) onSwipeDown()
                    else onSwipeUp()
                    return true
                }
            }
            return false
        }
    }

    open fun onSwipeLeft() {}
    open fun onSwipeRight() {}
    open fun onSwipeUp() {}
    open fun onSwipeDown() {}
}

OnSwipeTouchListenerはSimpleOnGestureListenerを拡張し、onFlingを実装します。diffX/diffYが方向を決定し、SWIPE_THRESHOLD(100px)とSWIPE_VELOCITY_THRESHOLD(100 px/s)がしきい値です。使用法:view.setOnTouchListener(OnSwipeTouchListener(context).apply { onSwipeLeft = { dismiss() } })。

例3:iOSでのSwipeActions(UITableView)

テーブルセルを左にスワイプしたときに削除ボタンを追加します。手動のジェスチャー認識なしで、組み込みのiOS 11+ APIを使用します。

swift
func tableView(
    _ tableView: UITableView,
    trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(
        style: .destructive,
        title: "削除"
    ) { _, _, completionHandler in
        items.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .automatic)
        completionHandler(true)
    }
    deleteAction.backgroundColor = .systemRed

    let config = UISwipeActionsConfiguration(actions: [deleteAction])
    config.performsFirstActionWithFullSwipe = true
    return config
}

メソッドはUIContextualActionの配列を含むUISwipeActionsConfigurationを返します。style: .destructiveは自動的に赤い背景を設定します。performsFirstActionWithFullSwipe = trueにより、追加のタップなしで完全なスワイプでアクションを実行できます。IT Sectrでは、アクション付きのすべてのリストにこのAPIを使用しています。標準化されており、VoiceOverをサポートし、カスタムのGestureRecognizerは必要ありません。

よくある質問

スワイプとパンニングの違いは何ですか?

スワイプは離散的なジェスチャーで、素早い動きと指の離脱を伴います。パンニングは座標追跡を伴う継続的なドラッグです。UISwipeGestureRecognizerは1回発火し、UIPanGestureRecognizerは.began → .changed → .endedを生成します。選択はシナリオによって異なります。スワイプはアクション(削除、めくる)用、panは移動(マップ、スライダー)用です。

スワイプはiOSとAndroidで同じように動作しますか?

ジェスチャーのロジックは同じですが、APIは異なります。iOSはUISwipeGestureRecognizerをdirectionと共に使用します。Androidはカスタムしきい値でGestureDetector.onFling()を使用します。結果は異なる実装で同じUXです。クロスプラットフォームフレームワーク(Flutter、React Native)は、統一されたスワイプAPIによって違いを抽象化します。

リストでスワイプを処理するにはどうすればよいですか?

iOS(11+)では、UITableViewDelegateでUISwipeActionsConfigurationを使用します。Androidでは、RecyclerViewにItemTouchHelper.SimpleCallbackを使用します。これらのAPIは手動のGestureRecognizerを置き換え、アクションボタンとアニメーションをサポートし、スクロールとの競合を適切に処理し、プラットフォームのHIGに適応します。

まとめ

  • スワイプは離散的な高速指スライドジェスチャーで、タップに次いで2番目に頻繁です(インタラクションの23%)。
  • iOSでは、UISwipeGestureRecognizerが約20pxの固定しきい値で4方向のスワイプを処理します。
  • Androidでは、GestureDetector.onFling()がカスタムの速度と距離のしきい値で使用されます。
  • リストでは、手動認識器の代わりにUISwipeActionsConfiguration(iOS)とItemTouchHelper(Android)を使用します。
  • スワイプは離散性と高速性においてパンニングと異なります。設計時にこれらのジェスチャーを混同しないでください。
  • AndroidのカスタムOnSwipeTouchListenerは、方向計算を隠蔽することでGestureDetector APIを簡素化します。
  • IT Sectrでは、ナビゲーション、アイテム削除、オンボーディングにスワイプを使用しています。このジェスチャーは直感的で学習が不要です。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください