Swipe: какво е това, обработка на плъзгания в мобилната разработка

Автор: IT Sectr Публикувано: 2026-02-27 Време за четене: 8 мин
Swipe (плъзгане) — дискретен жест, при който потребителят прекарва пръст по екрана в една посока — надясно, наляво, нагоре или надолу. За разлика от влаченето (drag), плъзгането не проследява непрекъснато движение: разпознава се като завършено действие след като пръстът премине минимален праг и се отдели от екрана. Според UX проучване на Nielsen Norman Group (2024), плъзгането е вторият най-чест жест в мобилните приложения след тапа, използван в 23% от потребителските взаимодействия.

Основни точки

  • Плъзгането — дискретен жест: разпознава се като едно завършено действие след преминаване на прага и отделяне на пръста.
  • В iOS обработката на плъзгане се извършва чрез UISwipeGestureRecognizer с настройка на посока (direction) и брой пръсти.
  • В 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 използваме плъзгане за навигация (галерии, картови интерфейси, onboarding) — този жест е интуитивен за потребители от всички възрасти.

Плъзгане vs панорамиране: каква е разликата?

Плъзгане и панорамиране (pan/drag) — различни типове жестове, въпреки че и двата използват движение на пръста по екрана. Плъзгането е дискретно и означава „направи едно действие”, докато панорамирането е непрекъснато и означава „премествай обекта, докато пръстът е на екрана”.

Параметър Плъзгане Панорамиране (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, достатъчна за надеждно разпознаване.

Тъй като UISwipeGestureRecogniser е дискретен разпознавател, не конфликтира с UIPanGestureRecognizer: при бавно движение ще се активира pan, при бързо — swipe. Въпреки това при съвместно съществуване с UITapGestureRecognizer на един и същ view може да се наложи 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 UISwipeGestureRecogniser обработва плъзгания в четири посоки с фиксиран праг ~20px.
  • В Android GestureDetector.onFling() се използва с персонализирани прагове на скорост и разстояние.
  • За списъци използвайте UISwipeActionsConfiguration (iOS) и ItemTouchHelper (Android) вместо ръчни разпознаватели.
  • Плъзгането се различава от панорамирането по дискретност и висока скорост — не бъркайте тези жестове при проектиране.
  • Персонализираният OnSwipeTouchListener в Android опростява API на GestureDetector, скривайки изчислението на посоката.
  • В IT Sectr прилагаме плъзгане за навигация, изтриване на елементи и onboarding — жестът е интуитивен и не изисква обучение.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също