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

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

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

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

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

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

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

Етапи розробки

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

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

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

Зум та пан виглядають як два gesture recognizer'а. Насправді це пов'язана система трансформацій, яка має працювати плавно на 60 fps, не конфліктувати з іншими жестами у застосунку та правильно обробляти edge cases — подвійне нажиття, межі зображення при панорамуванні, повернення в вихідний стан.

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

React Native — react-native-gesture-handler + react-native-reanimated. Стандартний <Image> не підтримує трансформації через жести — потрібні Animated.Image або Reanimated. Підхід з useSharedValue для scale та translateX/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.

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

Подвійне нажиття: якщо 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 format.

Галерея з зумом

Галерея: FlatList горизонтальний з pagingEnabled={true} (або ViewPager на Android). Кожен елемент — зумируємое зображення. Конфлікт жестів при горизонтальному пане — розруливаємо через activeOffsetX у Pan gesture handler: пан активується лише при зміщенні > 10px по горизонталі, поки scale > 1 блокуємо свайп сторінок.

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

  • Pinch-to-zoom з ограничением min/max scale (обычно 1x–5x)
  • Pan при збільшеному зображенні з обмеженням по межам
  • Подвійний тап — zoom in/out з анімацією в точку касання
  • Bounce-повернення при виході за межи
  • Інтеграція у галерею/карусель з правильним розв'язуванням конфліктів жестів
  • Підтримка високоразрешеных зображень без OutOfMemoryError

Строки

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