Asosiy fikrlar
Pinch-to-Zoom (chimdilash yoki siqish) — ko'rsatilgan kontent masshtabini o'zgartirish uchun ikki barmoqdai foydalanadigan ko'p sensorli jest. Barmoqlarni birlashtirganda (pinch close) masshtab kichrayadi, ochganda (pinch open) — kattalashadi. Jest uzluksiz: sistema barmoqlar orasidagi masofani real vaqtda kuzatib boradi va oraliq hodisalar yaratadi, bu ilovaga masshtabni silliq yangilash imkonini beradi.
Jest mexanikasi ikki teginish nuqtasi orasidagi masofani hisoblashga asoslanadi. iOS va Android Evklid masofasidan foydalanadi: sqrt((x2-x1)² + (y2-y1)²). Joriy scale joriy masofaning boshlang'ich masofaga nisbati sifatida hisoblanadi. Agar boshlang'ich masofa 100px bo'lib, 150px ga aylansa — scale = 1.5 (50% ga oshish). iOS scale ni oldingi holatga nisbatan (delta) uzatadi, Android esa ScaleGestureDetector orqali yig'ilgan scale ni uzatadi.
Google Material Design Guidelines ga ko'ra, Pinch-to-Zoom tasvirlar, xaritalar yoki hujjatlarni ko'rsatadigan ilovalar uchun majburiydir. IT Sectr da biz bu jestni UIPinchGestureRecognizer va ScaleGestureDetector bilan vizual kontent bilan ishlaydigan barcha loyihalarda — galereyalardan tortib tasvir muharrirlarigacha qo'llaymiz.
UIPinchGestureRecognizer — chimdilash jestini aniqlash uchun UIGestureRecognizer ning uzluksiz pastki sinfi. Diskret aniqlagichlardan (UITapGestureRecognizer) farqli o'laroq, hodisalar ketma-ketligini yaratadi: .began (barmoqlar ekranga tegdi), .changed (barmoqlarning har bir harakati), .ended (barmoqlar uzildi).
Asosiy xususiyatlar: scale (CGFloat) — jest boshidan barmoqlar orasidagi masofaning nisbiy o'zgarishi; velocity (CGFloat) — sekundiga scale o'zgarish tezligi. Boshlang'ich scale = 1.0. Barmoqlarni ochganda scale ortadi (1.0 → 1.5 → 2.0), birlashtirganda — kamayadi (1.0 → 0.8 → 0.5). Velocity xususiyati inertsiya uchun ishlatiladi: .ended dan keyin masshtablashni so'nish bilan davom ettirish animatsiyasi mumkin.
UIPinchGestureRecognizer boshqa aniqlagichlar bilan (masalan, xaritada pan + pinch) bir vaqtda ishlash uchun delegate xususiyatini qo'llab-quvvatlaydi. gestureRecognizer(_:shouldRecognizeSimultaneouslyWith()) metodi true qaytaradi va ikkala jest parallel ishlaydi. Apple UIPinchGestureRecognizer ni alohida elementlarga emas, konteyner view ga qo'shishni tavsiya qiladi — bu masshtablashning pivot nuqtasini hisoblashni soddalashtiradi.
ScaleGestureDetector — ko'p sensorli masshtablashni aniqlash uchun Android Support Library (android.view) dan sinf. GestureDetector.onFling dan farqli o'laroq, ScaleGestureDetector ikki barmoqli zoom uchun maxsus mo'ljallangan va avtomatik ravishda focusX, focusY (barmoqlar orasidagi markaz) va scaleFactor (oldingi hodisadan masshtab deltasi) ni hisoblab beradi.
ScaleGestureDetector uch metodli OnScaleGestureListener interfeysi orqali ishlaydi: onScaleBegin(detector) (.began analoqi), onScale(detector) (.changed analoqi, boolean qaytaradi — true agar masshtab qabul qilingan bo'lsa), onScaleEnd(detector) (.ended analoqi). Xususiyatlar: scaleFactor — oldingi hodisaga nisbatan masshtab ko'paytiruvchisi (~1.01 sekin ochishda), focusX/focusY — barmoqlar orasidagi markaz koordinatalari.
View ga masshtabni qo'llash uchun odatda Matrix ishlatiladi: view.imageMatrix.postScale(scaleFactor, scaleFactor, focusX, focusY). Matrix transformatsiyalarning yig'ilishini qo'llab-quvvatlaydi — har bir postScale chaqiruvi mavjud o'zgartirishga yangi o'zgartirish qo'shadi. Muhim: ScaleGestureDetector minimal/maksimal masshtabni cheklamaydi — bu dasturchining vazifasi. IT Sectr da biz ScaleGestureDetector ni maxsus scale chegaralari (0.5–3.0) va oshib ketishda qaytish animatsiyasi bilan qo'llaymiz.
Pinch-to-Zoom ni joriy qilishda minimal va maksimal masshtabni cheklash juda muhim — busiz foydalanuvchi tasvirni cheksizgacha kattalashtirishi yoki ko'rinmas darajada kichraytirishi mumkin. Standart qiymatlar: min = 0.5 (asl o'lchamning 50%), max = 3.0 (300%). iOS da cheklash clamp orqali amalga oshiriladi: newScale = min(max(currentScale * gesture.scale, minScale), maxScale). Android da — postScale dan keyin tekshirish orqali.
Pivot nuqtasi — masshtablash amalga oshiriladigan barmoqlar orasidagi markaz. iOS avtomatik ravishda ikki teginishning markazini hisoblab, uni location(in:) orqali uzatadi — dasturchi pivotni qo'lda hisoblashi shart emas. Android ScaleGestureDetector da focusX/focusY ni taqdim etadi, lekin Matrix orqali qo'llashda pivot postScale(scaleFactor, scaleFactor, focusX, focusY) da uchinchi va to'rtinchi argument sifatida uzatiladi. Pivot nuqtasisiz masshtablash yuqori chap burchakka (0,0) nisbatan amalga oshiriladi, bu zoom paytida kontentning siljishiga olib keladi.
IT Sectr tajribasiga ko'ra, pivot nuqtasini to'g'ri hisoblash — Pinch-to-Zoom ni joriy qilishda eng ko'p uchraydigan xato manbai. 90% hollarda GestureRecognizer va ScaleGestureDetector ning ichki koordinatalaridan foydalanish kifoya, pivotni qo'lda hisoblamasdan. Agar kontent masshtablash paytida siljisa — focusX/focusY ni matrix.postScale() ga uzatayotganingizni tekshiring.
Silliq UX uchun jest tugagandan so'ng inertsiya qo'shilishi mumkin: iOS da — UIPinchGestureRecognizer dan velocity ni spring parametrlari bilan UIView.animate uchun ishlating; Android da — OverScroller yoki ValueAnimator. Inertsiya min/max scale chegaralaridan chiqmasligi kerak — yakuniy qiymat oshib ketishda spring qaytish animatsiyasi bilan kesiladi.
UIImageView ga masshtab chegarasi 0.5 dan 3.0 gacha bo'lgan UIPinchGestureRecognizer qo'shadi. Yig'ilgan masshtabni saqlash bilan minimal joriy qilishni ko'rsatadi.
import UIKit
class ZoomableImageViewController: UIViewController {
@IBOutlet private var imageView: UIImageView!
private var currentScale: CGFloat = 1.0
private let minScale: CGFloat = 0.5
private let maxScale: CGFloat = 3.0
override func viewDidLoad() {
super.viewDidLoad()
let pinch = UIPinchGestureRecognizer(
target: self,
action: #selector(handlePinch(_:))
)
imageView.addGestureRecognizer(pinch)
imageView.isUserInteractionEnabled = true
}
@objc private func handlePinch(_: UIPinchGestureRecognizer) {
if gestureRecognizer.state == .began
|| gestureRecognizer.state == .changed {
let newScale = currentScale * gestureRecognizer.scale
imageView.transform = CGAffineTransform(
scaleX: min(max(newScale, minScale), maxScale),
y: min(max(newScale, minScale), maxScale)
)
}
if gestureRecognizer.state == .ended {
currentScale = min(max(
currentScale * gestureRecognizer.scale,
minScale
), maxScale)
gestureRecognizer.scale = 1.0
}
}
}
Mantiq: .began/.changed da masshtab CGAffineTransform orqali clamp bilan qo'llaniladi. .ended da scale 1.0 ga qaytariladi va yig'ilgan qiymat currentScale da saqlanadi. Bu ko'p jestlar paytida masshtabning "siljishi" ning oldini oladi — har bir yangi jest joriy holatdan boshlanadi. Tasvirlar uchun CGAffineTransform o'rniga minimumZoomScale/maximumZoomScale bilan UIScrollView tavsiya etiladi.
Matrix bilan ScaleGestureDetector orqali ImageView ni masshtablashni joriy qiladi. Pivot nuqtasini to'g'ri qayta ishlashni va masshtab cheklovini ko'rsatadi.
import android.content.Context
import android.graphics.Matrix
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.widget.ImageView
class PinchZoomImageView(context: Context) : ImageView(context) {
private val matrix = Matrix()
private var currentScale = 1f
private val minScale = 0.5f
private val maxScale = 3.0f
private val scaleDetector =
ScaleGestureDetector(context, ScaleListener())
private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector): Boolean {
currentScale = (currentScale * detector.scaleFactor)
.coerceIn(minScale, maxScale)
matrix.postScale(
currentScale,
currentScale,
detector.focusX,
detector.focusY
)
imageMatrix = matrix
return true
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
scaleDetector.onTouchEvent(event)
return true
}
}
Maxsus ImageView onTouchEvent ni bekor qilib, hodisalarni ScaleGestureDetector ga uzatadi. OnScaleListener.onScale() barmoqlarning har bir harakatida chaqiriladi. detector.scaleFactor — delta (sekin ochishda 1.01). currentScale clamp uchun coerceIn bilan yig'iladi. focusX/focusY — barmoqlar orasidagi markaz, to'g'ri pivot masshtablash uchun postScale ga uzatiladi.
UIScrollView delegate orqali o'rnatilgan Pinch-to-Zoom qo'llab-quvvatlashga ega. Bu tasvirlar va hujjatlar uchun afzal qilingan usul — ScrollView masshtabni, inertsiyani va aylantirishni avtomatik boshqaradi.
class ScrollableImageViewController: UIViewController,
UIScrollViewDelegate {
@IBOutlet private var scrollView: UIScrollView!
@IBOutlet private var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.minimumZoomScale = 0.5
scrollView.maximumZoomScale = 3.0
scrollView.delegate = self
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
}
UIScrollView mustaqil ravishda UIPinchGestureRecognizer yaratadi, CALayer transformatsiyasi orqali masshtabni boshqaradi va chegaralarni oshib ketganda bounce effekti qo'shadi. Kod min/maxZoomScale ni o'rnatish va viewForZooming ni qaytarishgacha qisqaradi. IT Sectr da biz barcha to'liq ekran tasvirlari uchun UIScrollView dan foydalanamiz — bu UIPinchGestureRecognizer orqali qo'lda joriy qilish bilan solishtirganda kod hajmini 5 baravar kamaytiradi.
Ko'p beriladigan savollar
Sensorli ekranda pinch ular orasidagi masofani kuzatish bilan ikki barmoqdan foydalanadi. MacBook trekpadida masshtablash bir xil holatlar (.began → .changed → .ended) bilan UIPinchGestureRecognizer orqali amalga oshiriladi, ammo teginish manbai sig'imli ekran emas, balki Force Touch bilan trekpad. API bir xil, mexanika bir xil.
iOS da: UIPinchGestureRecognizer dan scale olgandan so'ng currentScale ga ko'paytiring va clamp(min: 0.5, max: 3.0) qo'llang. Android da: matrix.postScale() dan oldin coerceIn(minScale, maxScale) orqali. UIScrollView da — minimumZoomScale va maximumZoomScale xususiyatlari orqali. Cheklovsiz masshtab cheksizlikka yoki nolga ketishi mumkin.
Yo'q, pinch kamida ikki barmoq talab qiladi. Bir barmoqli zoom (double-tap + yuqoriga/pastga surish) uchun UIPanGestureRecognizer yoki GestureDetector.onScroll orqali maxsus joriy qilish kerak. Bu boshqa mantiqqa ega boshqa jest — odatda kamera yoki xaritalarda zoom uchun ishlatiladi.
Xulosa
Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz
IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.