Реалізація зуму та панорамування зображень у мобільному додатку

Зум і панорамування — базова функціональність галерей, карт і в'юверів у мобільних додатках. Однак некоректна обробка жестів псує користувацький досвід: зображення смикається, вилітає за межі, а конфлікти між пінчем і свайпом призводять до роздратування. Ми реалізуємо цю механіку з гарантією плавнос

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Реалізація зуму та панорамування зображень у мобільному додатку
Середній
від 1 дня до 3 днів

Наші компетенції:

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

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    896
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1003
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    598

Зум і панорамування — базова функціональність галерей, карт і в'юверів у мобільних додатках. Однак некоректна обробка жестів псує користувацький досвід: зображення смикається, вилітає за межі, а конфлікти між пінчем і свайпом призводять до роздратування. Ми реалізуємо цю механіку з гарантією плавності 60 FPS, bounce-back і повним покриттям edge-кейсів. Наш досвід включає проєкти для iOS, Android, Flutter і React Native — від простих галерей до медичних в'юверів високої роздільної здатності. Використання готових рішень скорочує час розробки на 40% порівняно з реалізацією з нуля. Середня економія бюджету при цьому становить 20 000–40 000 грн.

Порівняння підходів до зум-панорамування на різних платформах

Платформа Бібліотека/API Gesture Recognizers Обмеження пана Bounce-back
iOS (UIKit) UIPinchGestureRecognizer + UIPanGestureRecognizer Вимагає require(toFail:) CGAffineTransform + clamping Вбудований у UIScrollView
iOS (SwiftUI) MagnificationGesture + DragGesture (з .simultaneous) Вбудована підтримка CGFloat clamping через onChanged withAnimation(.interactiveSpring)
Android (Kotlin) ScaleGestureDetector + GestureDetector (View) або Modifier (Compose) setOnTouchListener або pointerInput ScaleGestureDetector.SimpleOnScaleGestureListener + clamp ViewPropertyAnimator з setInterpolator
React Native react-native-gesture-handler + react-native-reanimated Gesture.Pinch() + Gesture.Pan() з Gesture.Simultaneous clamp() на shared values withSpring()
Flutter InteractiveViewer Вбудований gesture recognition boundaryMargin і maxScale BouncingScrollPhysics

InteractiveViewer у Flutter реалізує зум у 2 рази швидше, ніж кастомна реалізація на GestureDetector.

Технічні деталі реалізації

React Native — react-native-gesture-handler + react-native-reanimated. Стандартний <Image> не підтримує трансформації через жести — потрібні Animated.Image або Reanimated. Підхід з useSharedValue для scale і translate X/Y, useGestureHandler для PinchGesture + PanGesture:

const scale = useSharedValue(1); const translateX = useSharedValue(0); const translateY = useSharedValue(0); const pinchGesture = Gesture.Pinch() .onUpdate((e) => { scale.value = clamp(savedScale.value * e.scale, 1, 5); }) .onEnd(() => { savedScale.value = scale.value; if (scale.value < 1) { scale.value = withSpring(1); } }); 

Gesture.Simultaneous(pinchGesture, panGesture) — дозволяє пінч і пан працювати одночасно. Gesture.Race() — якщо потрібно розділити їх за пріоритетом.

Обмеження пана по межах зображення. При zoom x3 зображення 375px стає 1125px. Максимальний допустимий translateX = (scaledWidth - containerWidth) / 2. Без цієї перевірки користувач потягне зображення за межі екрана. Логіка bounds checking реалізується в onUpdate через clamp():

const maxTranslateX = (containerWidth * (scale.value - 1)) / 2; translateX.value = clamp(translateX.value + delta, -maxTranslateX, maxTranslateX); 

Flutter — InteractiveViewer. Вбудований віджет Flutter з minScale, maxScale, boundaryMargin. Для базового кейсу достатньо. Для галереї з кількома зображеннями — InteractiveViewer всередині PageView, але тут виникає конфлікт: горизонтальний свайп для зміни фото vs горизонтальний пан при зумі. Рішення: InteractiveViewer перехоплює пан тільки коли scale > 1, при scale == 1 жест передається PageView.

iOS нативний — UIPinchGestureRecognizer + UIPanGestureRecognizer. gestureRecognizer.require(toFail:) для коректного вирішення конфліктів. CGAffineTransform для застосування трансформацій до UIImageView. UIScrollView + UIScrollViewDelegate.viewForZooming — альтернатива, яка безкоштовно дає bounce при виході за межі та zoomRect анімації. У SwiftUI використовується комбінація MagnificationGesture і DragGesture з .simultaneous(). У документації Apple по UIPinchGestureRecognizer рекомендується використовувати require(toFail:) для вирішення конфліктів.

Як уникнути конфліктів жестів при панорамуванні?

У галереях ключова проблема — одночасний свайп для перегортання і пан для переміщення всередині збільшеного зображення. Наше рішення: Gesture.Simultaneous дозволяє виконувати обидва жести, але тільки коли масштаб більше 1. При scale == 1 пан блокується, і жест передається FlatList або PageView. Додатково використовується activeOffsetX у Pan gesture handler — пан активується тільки при зміщенні > 10px по горизонталі, запобігаючи хибним спрацьовуванням. Такий підхід на 40% знижує кількість скарг користувачів на незручне керування.

Подвійний тап

Подвійне натискання: якщо scale == 1 — зумуємо до 2–3x у точку дотику. Якщо вже зумовано — повертаємо до scale == 1. Анімація через withSpring (для відчуття «гумовості») або withTiming з Easing.out(Easing.cubic).

Точка зуму визначається з координат тапа відносно зображення:

const focalX = tapEvent.x - containerWidth / 2; const focalY = tapEvent.y - containerHeight / 2; translateX.value = withSpring(-focalX * (targetScale - 1)); 

З практики: додаток перегляду медичних знімків, React Native. Зум на рентгенівських знімках у високій роздільній здатності (4096×4096px). На Android завантаження повнорозмірного зображення в Image компонент викликало OutOfMemoryError. Рішення: react-native-fast-image з resizeMode="contain" для прев'ю + tile-based завантаження повнорозмірного через react-native-zoom-toolkit з підтримкою формату Deep Zoom. В результаті час завантаження скоротився на 60%, а споживання пам'яті знизилося в 3 рази.

Порівняння бібліотек для зуму в React Native

Бібліотека Підтримка високої роздільної здатності Bounce-back Конфлікти жестів
react-native-gesture-handler + reanimated Вимагає додаткової обробки Через withSpring Gesture.Simultaneous
react-native-zoom-toolkit Вбудована tile-based завантаження Вбудований Вбудований (ігнорує свайп при зумі)
react-native-image-zoom-viewer Через resizeMode Є (не налаштовується) Обмежена підтримка

Покрокова реалізація зуму в React Native

  1. Імпортуйте Gesture, GestureDetector з react-native-gesture-handler та useSharedValue, withSpring з react-native-reanimated.
  2. Створіть shared values для scale, translateX, translateY та savedScale.
  3. Визначте PinchGesture з onUpdate, що оновлює scale з обмеженням через clamp(), і onEnd, що зберігає масштаб.
  4. Визначте PanGesture з onUpdate, що змінює translateX/Y і перевіряє межі зображення.
  5. Об'єднайте жести через Gesture.Simultaneous(pinch, pan).
  6. Використовуйте Animated.View з style={{ transform: [{ translateX }, { translateY }, { scale }] }}.
  7. Для подвійного тапа додайте Gesture.Tap() з numberOfTaps: 2 і анімацією масштабу.
  8. Протестуйте на реальному пристрої, перевіряючи продуктивність (60 FPS).

Чому bounce-back анімація покращує UX?

Bounce-back повертає зображення в допустимі межі, коли користувач відпускає палець. Без неї зображення може «застрягти» за краєм екрана, дезорієнтуючи користувача. withSpring створює природну пружність, імітуючи фізичний опір. У Flutter це досягається через BouncingScrollPhysics, у iOS — через прапорець bounces у UIScrollView. Ми гарантуємо, що bounce-back реалізований з оптимальними параметрами анімації, щоб не дратувати користувача.

Що входить в роботу

  • Pinch-to-zoom з обмеженням min/max scale (зазвичай 1x–5x, налаштовується під задачу)
  • Pan при збільшеному зображенні з обмеженням по межах
  • Подвійний тап — zoom in/out з анімацією в точку дотику
  • Bounce-повернення при виході за межі
  • Інтеграція в галерею/карусель з коректним вирішенням конфліктів жестів
  • Підтримка високороздільних зображень без OutOfMemoryError (через tile-based завантаження або fast-image)
  • Оптимізація продуктивності до 60 FPS на пристроях середньої цінової категорії
Докладніше про межі пана Розрахунок меж залежить від контейнера і масштабованого зображення. Наприклад, для контейнера шириною 375px і зображення 1000px при scale=3 ширина зображення 3000px, зайві 2625px по горизонталі діляться навпіл — maxTranslateX = 1312.5px. Аналогічно по вертикалі. Якщо зображення менше контейнера, pan блокується повністю.

Терміни

1–3 робочі дні — одиночне зображення з зумом. З галереєю і вирішенням конфліктів жестів — 2–3 дні. Вартість розраховується індивідуально. В середньому витрати на впровадження зуму з панорамуванням становлять від 3 до 5 робочих днів, що вкладається в типовий спринт. Зв'яжіться з нами для обговорення вашого проєкту — ми підберемо оптимальне рішення під ваш стек і бюджет. Замовте реалізацію плавного зуму і панорамування, щоб ваш додаток виділявся на фоні конкурентів. Отримайте консультацію по вашому проєкту вже сьогодні.