Swipe: що це, обробка свайпів у мобільній розробці

Автор: IT Sectr Опубліковано: 2026-02-27 Час читання: 8 хв
Swipe (свайп) — дискретний жест, при якому користувач проводить пальцем по екрану в одному напрямку — вправо, вліво, вгору або вниз. На відміну від перетягування (drag), свайп не відстежує безперервний рух: він розпізнається як завершена дія після того, як палець подолав мінімальний поріг і відірвався від екрану. За даними UX-дослідження Nielsen Norman Group (2024), свайп — другий за частотою жест у мобільних додатках після тапу, який використовується у 23% користувацьких взаємодій.

Головне

  • Swipe — дискретний жест: розпізнається як одна завершена дія після проходження порогу та відриву пальця.
  • В iOS обробка свайпу виконується через UISwipeGestureRecognizer з налаштуванням напрямку та кількості пальців.
  • В Android використовується GestureDetector з onFling(MotionEvent) або OnSwipeTouchListener для спрощеного API.
  • Поріг свайпу — ~20px на iOS (viewConfiguration) та налаштовується через VelocityTracker в Android.
  • Для списків (UITableView/RecyclerView) використовуються вбудовані механізми — UISwipeActionsConfiguration та ItemTouchHelper — замість ручного розпізнавання.

Що таке свайп?

Свайп — це швидкий ковзний рух пальцем по поверхні екрану, який завершується відривом. Свайп може бути коротким (гортання елемента) або довгим (відкриття шторки), але ключова характеристика — дискретність: система розпізнає його як одну подію, а не як безперервну послідовність координат.

Мобільні ОС визначають свайп за трьома параметрами: мінімальна відстань (поріг), мінімальна швидкість (velocity) та напрямок. Якщо палець рухається повільно або відстань недостатня, система інтерпретує жест як панорамування (pan) або тап. Порогові значення відрізняються між платформами: iOS використовує константу UISwipeGestureRecognizer з фіксованим порогом, Android — ViewConfiguration.getScaledTouchSlop(), який повертає ~8–16 dp залежно від щільності екрану.

Згідно з Android Developers Documentation, onFling (свайп) в GestureDetector спрацьовує при швидкості вище 100 px/s та відстані від 50px. В IT Sectr ми використовуємо свайп для навігації (галереї, карткові інтерфейси, онбординг) — цей жест інтуїтивно зрозумілий користувачам будь-якого віку.

Свайп vs панорамування: у чому різниця?

Свайп і панорамування (pan/drag) — різні типи жестів, хоча обидва використовують рух пальця по екрану. Свайп дискретний і означає «зробити одну дію», тоді як панорамування безперервне і означає «переміщати об'єкт, поки палець на екрані».

Параметр Свайп (Swipe) Панорамування (Pan/Drag)
Тип Дискретний Безперервний
Події Одна (розпізнано/не розпізнано) Багато (.began → .changed → .ended)
Швидкість Висока (швидкий рух) Будь-яка (повільний рух)
Приклад iOS UISwipeGestureRecognizer UIPanGestureRecognizer
Приклад Android GestureDetector.onFling() GestureDetector.onScroll()
Сценарій Видалити лист, перегорнути сторінку Перемістити карту, перетягнути файл
Відстеження координат Ні (тільки напрямок) Так (постійне оновлення координат)

Вибір між свайпом і панорамуванням залежить від завдання. Для дій з елементом (видалити, архівувати, відкрити меню) використовуйте свайп. Для прямого маніпулювання (переміщення, масштабування) — панорамування. Змішування жестів на одному елементі вимагає require(toFail:) або кастомної логіки.

Свайп в iOS: UISwipeGestureRecognizer

UISwipeGestureRecognizer — підклас UIGestureRecognizer, який розпізнає дискретний свайп в одному з чотирьох напрямків. На відміну від UIPanGestureRecognizer, він не генерує проміжні .changed-події: при розпізнаванні action викликається рівно один раз.

Властивість 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 для розпізнавання свайпу — GestureDetector з колбеком OnGestureListener, а саме метод onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY). GestureDetector аналізує початкове та кінцеве положення пальця, швидкість руху по осях та відстань, після чого викликає onFling при перевищенні порогів.

Мінімальні пороги налаштовуються через ViewConfiguration: VelocityTracker.getMinVelocity() (~100 px/s) та ViewConfiguration.getScaledTouchSlop() (~8–16 dp). Кастомний OnSwipeTouchListener — поширений патерн, який спрощує API: розробнику не потрібно вручну обчислювати напрямок та швидкість. Android Support Library не містить вбудованого «SwipeDetector», тому кастомна обгортка — стандартне рішення.

Для свайпу в списках Google рекомендує використовувати ItemTouchHelper.SimpleCallback з RecyclerView, який абстрагує детекцію жесту, анімацію та колбеки onSwiped(). В IT Sectr ми використовуємо кастомний SwipeListener для ViewPager2 та карткових інтерфейсів — це дає контроль над чутливістю свайпу без шкоди для продуктивності.

Свайп у списках: SwipeActions та ItemTouchHelper

Для списків (UITableView, RecyclerView) Apple та Google надають спеціалізовані API, які замінюють ручне додавання UISwipeGestureRecognizer. Ці API підтримують кнопки дій, кастомну анімацію та жести «проведи, щоб видалити» — стандартні патерни мобільних додатків.

В iOS (11+) використовується UISwipeActionsConfiguration: метод tableView(_:leadingSwipeActionsConfigurationForRowAt:) повертає масив UIContextualAction — кнопок із заголовком, стилем (destructive, normal) та обробником. Наприклад, «Видалити» — .destructive з червоним фоном, «Архів» — .normal з сірим. Система сама анімує появу кнопок і викликає completion-блок після натискання.

В Android ItemTouchHelper.SimpleCallback прикріплюється до RecyclerView через ItemTouchHelper.attachToRecyclerView(). Параметри — прапорці напрямків (start, end, up, down) та колбек onSwiped(viewHolder, direction). Всередині onSwiped викликається adapter.notifyItemRemoved(position) для видалення елемента з анімацією. ItemTouchHelper автоматично обробляє жести, конфлікти з прокруткою (scroll) та повернення елемента, якщо свайп не завершено. За даними Google I/O 2024, ItemTouchHelper використовується в 70% Android-додатків зі свайп-діями в списках.

Приклади коду на Swift та Kotlin

Приклад 1: Свайп вліво на iOS (Swift)

Додає UISwipeGestureRecognizer на view для повернення до попереднього екрану. Код показує мінімальну конфігурацію розпізнавача з напрямком .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)
        }
    }
}

Розпізнавач прив'язується до root-view контролера. Перевірка navigationController.viewControllers.count гарантує, що pop виконується лише за наявності попереднього екрану в стеку. Для модальних контролерів використовується dismiss. Код не вимагає перевірки state — UISwipeGestureRecognizer дискретний і викликає action тільки при успішному розпізнаванні.

Приклад 2: Свайп в Android (Kotlin) з кастомним OnSwipeTouchListener

Реалізує просту обгортку GestureDetector, яка визначає напрямок свайпу та викликає колбеки onSwipeLeft/Right.

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: SwipeActions в iOS (UITableView)

Додає кнопку видалення при свайпі вліво по комірці таблиці. Використовує вбудований API iOS 11+ без ручного розпізнавання жестів.

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
}

Метод повертає UISwipeActionsConfiguration з масивом UIContextualAction. style: .destructive автоматично задає червоний фон. performsFirstActionWithFullSwipe = true дозволяє виконати дію повним свайпом без додаткового натискання. В IT Sectr ми використовуємо цей API для всіх списків з діями — він стандартизований, підтримує VoiceOver і не вимагає кастомних GestureRecognizer.

Часті запитання

Як відрізнити свайп від панорамування?

Свайп — дискретний жест із швидким рухом та відривом пальця, панорамування — безперервне перетягування з відстеженням координат. UISwipeGestureRecognizer спрацьовує один раз, UIPanGestureRecognizer генерує .began → .changed → .ended. Вибір залежить від сценарію: свайп — для дій (видалити, перегорнути), pan — для переміщення (карта, слайдер).

Свайп працює однаково на iOS та Android?

Логіка жесту ідентична, але API відрізняється. iOS використовує UISwipeGestureRecognizer з direction. Android використовує GestureDetector.onFling() з кастомними порогами. Результат — однаковий UX при різній реалізації. Кроссплатформенні фреймворки (Flutter, React Native) абстрагують різницю через єдиний API свайпу.

Як обробити свайп у списку?

В iOS (11+) використовуйте UISwipeActionsConfiguration в UITableViewDelegate. В Android — ItemTouchHelper.SimpleCallback для RecyclerView. Ці API замінюють ручні GestureRecognizer, підтримують кнопки дій та анімацію, коректно обробляють конфлікт з прокруткою та адаптуються під платформенні HIG.

Підсумки

  • Свайп — дискретний жест швидкого ковзання пальцем, другий за частотою після тапу (23% взаємодій).
  • В iOS UISwipeGestureRecognizer обробляє свайпи в чотирьох напрямках з фіксованим порогом ~20px.
  • В Android GestureDetector.onFling() використовується з кастомними порогами швидкості та відстані.
  • Для списків використовуйте UISwipeActionsConfiguration (iOS) та ItemTouchHelper (Android) замість ручних розпізнавачів.
  • Свайп відрізняється від панорамування дискретністю та високою швидкістю — не плутайте ці жести при проектуванні.
  • Кастомний OnSwipeTouchListener в Android спрощує API GestureDetector, приховуючи обчислення напрямку.
  • В IT Sectr ми застосовуємо свайп для навігації, видалення елементів та онбордингу — жест інтуїтивний і не потребує навчання.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також