Gesture Navigation — е система за управление на мобилно приложение чрез сензорни жестове, която замени хардуерните бутони на повечето модерни смартфони. Според Android Developers (2024), жестовата навигация стана стандарт от Android 10, а Apple премина към жестове още с iPhone X през 2017 г. Системата включва swipe, pinch, double tap и long press — всеки жест има определено предназначение в контекста на екрана. Разбирането на архитектурата на жестовата навигация е необходимо за създаването на интуитивни и отзивчиви интерфейси.
Основни точки
Gesture Navigation — е метод за взаимодействие на потребителя с мобилно устройство чрез последователности от докосвания, движения и натискания, разпознавани от сензорния екран. За разлика от традиционните бутони, жестовете нямат фиксирана позиция на екрана и се разпознават по модела на движение: swipe от ръба, pinch с два пръста, дълго натискане.
Преходът към жестова навигация започна с iPhone X (2017), където Apple напълно премахна бутона Home, заменяйки го със swipe от долния ръб. Google последва тенденцията в Android 10 (2020), предлагайки на потребителите избор: навигация с три бутона, навигация с два бутона и пълна жестова навигация. Според StatCounter (2025), над 75% от Android устройствата и 95% от iOS устройствата използват жестова навигация.
Архитектурно, разпознаването на жестове се състои от три етапа: Capture (улавяне на сензорни събития), Recognition (определяне на модела на движение) и Action (изпълнение на зададеното действие). На системно ниво Android и iOS имат вградени обработващи програми за основни навигационни жестове — swipe назад, преминаване към началния екран, отваряне на превключвателя на приложения. Разработчикът трябва само правилно да интегрира своите жестове в тази система.
Всички сензорни жестове могат да бъдат разделени в три категории според целта и начина на изпълнение. Всеки вид има свои правила за обработка и препоръки за използване в интерфейса.
Навигационните жестове управляват придвижването между екрани: swipe от левия ръб за връщане назад (iOS), swipe нагоре за отваряне на превключвателя на приложения, swipe от долния ръб за връщане към началния екран. Тези жестове се обработват от системата на ниво Window и не трябва да влизат в конфликт с потребителските жестове вътре в приложението.
Манипулационните жестове променят позицията, размера или ориентацията на обекти на екрана. Pinch (мащабиране с два пръста), Rotate (завъртане), Pan (влачене), Swipe (бързо swipe за прелистване) — всички тези жестове се обработват на ниво View или Composabale и не засягат системната навигация.
Контекстните жестове активират допълнителни функции без преминаване към друг екран. Long press (дълго натискане за контекстно меню), Double tap (двойно натискане за харесване или мащабиране), Edge swipe (swipe от ръба за отваряне на Drawer). Тези жестове изискват най-внимателно имплементиране, тъй като могат да се припокриват със системните навигационни жестове.
| Вид жест | Пример | Ниво на обработка | Конфликт със системата |
|---|---|---|---|
| Навигационни | Swipe назад | Window / System | Първичен |
| Манипулационни | Pinch zoom | View | Не |
| Контекстни | Long press | View | Възможен |
Android SDK предоставя многослойна система за обработка на жестове, започвайки от ниско ниво MotionEvent до високо ниво GestureDetector и GestureOverlayView. Правилният избор на ниво зависи от сложността на жеста и изискванията за производителност.
GestureDetector — е клас от високо ниво, който преобразува последователност от MotionEvent в конкретни жестове: onDown, onShowPress, onSingleTapUp, onScroll, onLongPress, onFling. Разработчикът презаписва необходимите методи на GestureDetector.SimpleOnGestureListener и получава готовото разпознато събитие. GestureDetector се препоръчва за всички стандартни жестове, с изключение на мащабирането — за това има ScaleGestureDetector.
val gestureDetector = GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
override fun onFling(
e1: MotionEvent?, e2: MotionEvent,
velocityX: Float, velocityY: Float
): Boolean {
val deltaX = e2.x - (e1?.x ?: 0f)
return if (Math.abs(deltaX) > Math.abs(e2.y - (e1?.y ?: 0f))) {
if (deltaX > 0) onSwipeRight() else onSwipeLeft()
true
} else false
}
})
view.setOnTouchListener { _, event -> gestureDetector.onTouchEvent(event) }
TouchDelegate — механизъм за разширяване на зоната на докосване за View. Използва се, когато целевият елемент е по-малък от минималния размер на докосване 48dp. Например, малък бутон „Затвори" в ъгъла на екрана получава TouchDelegate, който разширява неговата зона на удар без промяна на видимия размер. Google препоръчва TouchDelegate за всички интерактивни елементи, по-малки от 48x48dp.
Compose предоставя модификатори за обработка на жестове: clickable, draggable, swipeable, combinedClickable (за double tap и long press). Вътрешно, Compose използва PointerInputScope за ниско ниво на обработка, но за повечето разработчици са достатъчни модификаторите от високо ниво. За персонализирани жестове се използва pointerInput с awaitPointerEvent.
iOS SDK използва архитектурата UIGestureRecognizer — абстрактен базов клас, който анализира последователност от UITouch и определя дали тя съответства на познат жест. Apple препоръчва използването на стандартни разпознавачи, където е възможно, и създаване на персонализирани подкласове само за уникални жестове.
UIKit предоставя набор от готови разпознавачи: UITapGestureRecognizer, UISwipeGestureRecognizer, UIPanGestureRecognizer, UIPinchGestureRecognizer, UIRotationGestureRecognizer, UILongPressGestureRecognizer. Всеки разпознавач има състояния (possible, began, changed, ended, cancelled, failed) — разработчикът следи състоянието, за да реагира на различни етапи от жеста.
let swipeBack = UISwipeGestureRecognizer(
target: self,
action: #selector(handleSwipeBack)
)
swipeBack.direction = .right
view.addGestureRecognizer(swipeBack)
@objc func handleSwipeBack() {
navigationController?.popViewController(animated: true)
}
SwiftUI използва декларативни модификатори на жестове, подобно на Compose: onTapGesture, onLongPressGesture, MagnificationGesture, RotationGesture, DragGesture. SwiftUI автоматично обработва конфликти между жестове чрез simultaneousGesture, sequencedGesture и exclusiveGesture — модификатори, които определят приоритета на жестовете при едновременно задействане.
Image("photo")
.gesture(
MagnificationGesture()
.onChanged { scale in
self.currentScale = scale
}
.sequenced(before: DragGesture())
)
InteractivePopGestureRecognizer — системен разпознавач, който управлява swipe назад в UINavigationController. По подразбиране е активен за всички екрани, с изключение на основния. Ако вашето приложение използва персонализиран NavigationBar, interactivePopGestureRecognizer може да спре да работи — ще се изисква програмно активиране чрез navigationController.interactivePopGestureRecognizer?.delegate.
Конфликт на жестове — един от най-трудните проблеми в жестовата навигация. Когато потребителски жест (например, отваряне на Drawer чрез swipe от левия ръб) се припокрива със системен жест (swipe назад на iOS или Android), системата трябва да определи кой жест има приоритет. Правилното обработване на този конфликт е критично за UX.
Android 10+ позволява на приложението да резервира зони на екрана за своите жестове чрез WindowInsets. Използвайте ViewCompat.setSystemGestureExclusionRects, за да посочите региони, където системните жестове не трябва да работят. Например, за Drawer отляво можете да изключите левия ръб на екрана (ширина до 200dp) от системния swipe назад. Google е поставил лимит: до 200dp от всяка страна могат да бъдат изключени.
val exclusionRect = Rect(0, 0, 200, height)
ViewCompat.setSystemGestureExclusionRects(
drawerView,
listOf(SystemGestureExclusionRect(exclusionRect))
)
iOS предоставя метода gestureRecognizerShouldBegin в UIGestureRecognizerDelegate, който позволява на персонализиран разпознавач да реши дали трябва да започне разпознаване. За Drawer swipe от левия ръб можете да проверите позицията на докосване: ако потребителят тегли Drawer (разстояние по-голямо от threshold), персонализираният жест поема контрола. Ако жестът не бъде разпознат, системата връща контрола на InteractivePopGestureRecognizer.
Gesture Navigation изисква внимателно проектиране, особено на устройства със системна жестова навигация. Нека разгледаме честите грешки и препоръките за тяхното отстраняване.
Най-честата грешка — поставяне на интерактивни елементи или имплементиране на персонализирани свайпове в зони на системни жестове (ляв и десен ръб, долен ръб). Потребителят се опитва да извърши действие, а вместо това се активира системната навигация. Винаги предвиждайте разстояние за системните жестове и обработвайте конфликтите чрез exclusion rects.
Параметрите на жестовете (velocity threshold, minimum distance) се различават по подразбиране между платформите. Ако вашето приложение е кросплатформено, не копирайте параметрите от една платформа на друга — тествайте всеки жест отделно на Android и iOS. Flutter и React Native автоматично адаптират някои параметри, но не всички.
Всеки жест трябва да бъде придружен от визуална обратна връзка: промяна на цвят, трансформация, анимация. Потребителят трябва да разбере, че жестът е разпознат и действието се изпълнява. На iOS системните разпознавачи автоматично предоставят хаптична обратна връзка, на Android тя трябва да бъде добавена чрез HapticFeedbackConstants.
Не всички потребители могат да изпълняват жестове — хора с ограничена моторика използват VoiceOver и TalkBack за навигация. За всеки жест трябва да съществува алтернатива под формата на бутон. Google и Apple изискват всички действия с жестове да бъдат дублирани с достъпни контролни елементи.
Често задавани въпроси
iOS — Apple въведе жестова навигация с iPhone X през 2017 г., заменяйки бутона Home със swipe от долния ръб. Android последва примера в Android 10 (2020), предлагайки жестове като алтернатива на бутоните.
Swipe — бързо движение с висока velocity (пиксела/сек) и прекъсващо. Scroll — бавно движение с ниска velocity и непрекъснато. Използвайте velocityX/Y за различаване: прагът обикновено е 500-1000 px/s в зависимост от платформата.
Не — Android и iOS не позволяват на приложението да изключи системната жестова навигация. Можете само да резервирате зони на екрана чрез exclusion rects (Android) или gestureRecognizerShouldBegin (iOS).
Android Emulator поддържа мултитъч чрез Ctrl+клик (добавяне на втори пръст). iOS Simulator — чрез Option+клик за два пръста. Flutter test използва WidgetTester.timedDrag за симулация на свайпове в unit тестове.
Gesture War — конфликт между два разпознавача, когато и двата се опитват да обработят едно докосване. Избягвайте чрез приоритети: в iOS използвайте require(toFail:), в Compose — sequentialGesture и exclusiveGesture. Flutter използва GestureArena за автоматично разрешаване.
Заключение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също